@quereus/quereus 4.8.0 → 4.10.0

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 (280) hide show
  1. package/dist/src/core/database.d.ts +6 -0
  2. package/dist/src/core/database.d.ts.map +1 -1
  3. package/dist/src/core/database.js +45 -5
  4. package/dist/src/core/database.js.map +1 -1
  5. package/dist/src/core/statement.d.ts.map +1 -1
  6. package/dist/src/core/statement.js +74 -15
  7. package/dist/src/core/statement.js.map +1 -1
  8. package/dist/src/func/builtins/aggregate.d.ts.map +1 -1
  9. package/dist/src/func/builtins/aggregate.js +88 -35
  10. package/dist/src/func/builtins/aggregate.js.map +1 -1
  11. package/dist/src/func/builtins/conversion.d.ts +5 -0
  12. package/dist/src/func/builtins/conversion.d.ts.map +1 -1
  13. package/dist/src/func/builtins/conversion.js +16 -2
  14. package/dist/src/func/builtins/conversion.js.map +1 -1
  15. package/dist/src/func/builtins/explain.d.ts.map +1 -1
  16. package/dist/src/func/builtins/explain.js +9 -2
  17. package/dist/src/func/builtins/explain.js.map +1 -1
  18. package/dist/src/func/builtins/index.d.ts.map +1 -1
  19. package/dist/src/func/builtins/index.js +5 -2
  20. package/dist/src/func/builtins/index.js.map +1 -1
  21. package/dist/src/func/builtins/scalar.d.ts.map +1 -1
  22. package/dist/src/func/builtins/scalar.js +4 -2
  23. package/dist/src/func/builtins/scalar.js.map +1 -1
  24. package/dist/src/func/builtins/string.d.ts +2 -0
  25. package/dist/src/func/builtins/string.d.ts.map +1 -1
  26. package/dist/src/func/builtins/string.js +60 -4
  27. package/dist/src/func/builtins/string.js.map +1 -1
  28. package/dist/src/func/registration.d.ts +6 -0
  29. package/dist/src/func/registration.d.ts.map +1 -1
  30. package/dist/src/func/registration.js +1 -0
  31. package/dist/src/func/registration.js.map +1 -1
  32. package/dist/src/index.d.ts +7 -3
  33. package/dist/src/index.d.ts.map +1 -1
  34. package/dist/src/index.js +21 -2
  35. package/dist/src/index.js.map +1 -1
  36. package/dist/src/planner/building/constraint-builder.js +1 -1
  37. package/dist/src/planner/building/constraint-builder.js.map +1 -1
  38. package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
  39. package/dist/src/planner/nodes/scalar.js +13 -1
  40. package/dist/src/planner/nodes/scalar.js.map +1 -1
  41. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.d.ts.map +1 -1
  42. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +121 -51
  43. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
  44. package/dist/src/planner/rules/shared/index-style-context.d.ts +14 -4
  45. package/dist/src/planner/rules/shared/index-style-context.d.ts.map +1 -1
  46. package/dist/src/planner/rules/shared/index-style-context.js +14 -4
  47. package/dist/src/planner/rules/shared/index-style-context.js.map +1 -1
  48. package/dist/src/runtime/emission-context.d.ts +14 -1
  49. package/dist/src/runtime/emission-context.d.ts.map +1 -1
  50. package/dist/src/runtime/emission-context.js +17 -5
  51. package/dist/src/runtime/emission-context.js.map +1 -1
  52. package/dist/src/runtime/emit/aggregate-setup.d.ts +44 -8
  53. package/dist/src/runtime/emit/aggregate-setup.d.ts.map +1 -1
  54. package/dist/src/runtime/emit/aggregate-setup.js +79 -15
  55. package/dist/src/runtime/emit/aggregate-setup.js.map +1 -1
  56. package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
  57. package/dist/src/runtime/emit/aggregate.js +21 -106
  58. package/dist/src/runtime/emit/aggregate.js.map +1 -1
  59. package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
  60. package/dist/src/runtime/emit/alter-table.js +212 -155
  61. package/dist/src/runtime/emit/alter-table.js.map +1 -1
  62. package/dist/src/runtime/emit/asof-scan.js +1 -1
  63. package/dist/src/runtime/emit/asof-scan.js.map +1 -1
  64. package/dist/src/runtime/emit/assertion-drop-guard.d.ts +26 -12
  65. package/dist/src/runtime/emit/assertion-drop-guard.d.ts.map +1 -1
  66. package/dist/src/runtime/emit/assertion-drop-guard.js +45 -26
  67. package/dist/src/runtime/emit/assertion-drop-guard.js.map +1 -1
  68. package/dist/src/runtime/emit/assertion-rename-helpers.d.ts +6 -6
  69. package/dist/src/runtime/emit/assertion-rename-helpers.d.ts.map +1 -1
  70. package/dist/src/runtime/emit/assertion-rename-helpers.js +18 -20
  71. package/dist/src/runtime/emit/assertion-rename-helpers.js.map +1 -1
  72. package/dist/src/runtime/emit/between.d.ts +2 -0
  73. package/dist/src/runtime/emit/between.d.ts.map +1 -1
  74. package/dist/src/runtime/emit/between.js +7 -8
  75. package/dist/src/runtime/emit/between.js.map +1 -1
  76. package/dist/src/runtime/emit/binary.d.ts +27 -5
  77. package/dist/src/runtime/emit/binary.d.ts.map +1 -1
  78. package/dist/src/runtime/emit/binary.js +278 -187
  79. package/dist/src/runtime/emit/binary.js.map +1 -1
  80. package/dist/src/runtime/emit/case.d.ts +34 -0
  81. package/dist/src/runtime/emit/case.d.ts.map +1 -1
  82. package/dist/src/runtime/emit/case.js +18 -11
  83. package/dist/src/runtime/emit/case.js.map +1 -1
  84. package/dist/src/runtime/emit/cast.d.ts +2 -0
  85. package/dist/src/runtime/emit/cast.d.ts.map +1 -1
  86. package/dist/src/runtime/emit/cast.js +7 -5
  87. package/dist/src/runtime/emit/cast.js.map +1 -1
  88. package/dist/src/runtime/emit/column-reference.d.ts +3 -1
  89. package/dist/src/runtime/emit/column-reference.d.ts.map +1 -1
  90. package/dist/src/runtime/emit/column-reference.js +6 -2
  91. package/dist/src/runtime/emit/column-reference.js.map +1 -1
  92. package/dist/src/runtime/emit/column-rename-cascade.d.ts +84 -0
  93. package/dist/src/runtime/emit/column-rename-cascade.d.ts.map +1 -0
  94. package/dist/src/runtime/emit/column-rename-cascade.js +134 -0
  95. package/dist/src/runtime/emit/column-rename-cascade.js.map +1 -0
  96. package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
  97. package/dist/src/runtime/emit/dml-executor.js +21 -0
  98. package/dist/src/runtime/emit/dml-executor.js.map +1 -1
  99. package/dist/src/runtime/emit/drop-column-guards.d.ts +82 -53
  100. package/dist/src/runtime/emit/drop-column-guards.d.ts.map +1 -1
  101. package/dist/src/runtime/emit/drop-column-guards.js +155 -90
  102. package/dist/src/runtime/emit/drop-column-guards.js.map +1 -1
  103. package/dist/src/runtime/emit/drop-table.d.ts.map +1 -1
  104. package/dist/src/runtime/emit/drop-table.js +5 -0
  105. package/dist/src/runtime/emit/drop-table.js.map +1 -1
  106. package/dist/src/runtime/emit/drop-view.d.ts.map +1 -1
  107. package/dist/src/runtime/emit/drop-view.js +5 -0
  108. package/dist/src/runtime/emit/drop-view.js.map +1 -1
  109. package/dist/src/runtime/emit/expression-drop-guard.d.ts +57 -0
  110. package/dist/src/runtime/emit/expression-drop-guard.d.ts.map +1 -0
  111. package/dist/src/runtime/emit/expression-drop-guard.js +82 -0
  112. package/dist/src/runtime/emit/expression-drop-guard.js.map +1 -0
  113. package/dist/src/runtime/emit/filter.d.ts +1 -1
  114. package/dist/src/runtime/emit/filter.js +1 -1
  115. package/dist/src/runtime/emit/hash-aggregate.d.ts.map +1 -1
  116. package/dist/src/runtime/emit/hash-aggregate.js +18 -88
  117. package/dist/src/runtime/emit/hash-aggregate.js.map +1 -1
  118. package/dist/src/runtime/emit/literal.d.ts +14 -1
  119. package/dist/src/runtime/emit/literal.d.ts.map +1 -1
  120. package/dist/src/runtime/emit/literal.js +33 -7
  121. package/dist/src/runtime/emit/literal.js.map +1 -1
  122. package/dist/src/runtime/emit/materialized-view-helpers.d.ts +33 -10
  123. package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -1
  124. package/dist/src/runtime/emit/materialized-view-helpers.js +158 -49
  125. package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -1
  126. package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -1
  127. package/dist/src/runtime/emit/materialized-view.js +3 -0
  128. package/dist/src/runtime/emit/materialized-view.js.map +1 -1
  129. package/dist/src/runtime/emit/parameter.d.ts +3 -1
  130. package/dist/src/runtime/emit/parameter.d.ts.map +1 -1
  131. package/dist/src/runtime/emit/parameter.js +7 -2
  132. package/dist/src/runtime/emit/parameter.js.map +1 -1
  133. package/dist/src/runtime/emit/scalar-function.d.ts +29 -1
  134. package/dist/src/runtime/emit/scalar-function.d.ts.map +1 -1
  135. package/dist/src/runtime/emit/scalar-function.js +66 -16
  136. package/dist/src/runtime/emit/scalar-function.js.map +1 -1
  137. package/dist/src/runtime/emit/scalar-op.d.ts +63 -0
  138. package/dist/src/runtime/emit/scalar-op.d.ts.map +1 -0
  139. package/dist/src/runtime/emit/scalar-op.js +37 -0
  140. package/dist/src/runtime/emit/scalar-op.js.map +1 -0
  141. package/dist/src/runtime/emit/scan.d.ts.map +1 -1
  142. package/dist/src/runtime/emit/scan.js +19 -1
  143. package/dist/src/runtime/emit/scan.js.map +1 -1
  144. package/dist/src/runtime/emit/temporal-arithmetic.d.ts +18 -8
  145. package/dist/src/runtime/emit/temporal-arithmetic.d.ts.map +1 -1
  146. package/dist/src/runtime/emit/temporal-arithmetic.js +29 -311
  147. package/dist/src/runtime/emit/temporal-arithmetic.js.map +1 -1
  148. package/dist/src/runtime/emit/unary.d.ts +2 -0
  149. package/dist/src/runtime/emit/unary.d.ts.map +1 -1
  150. package/dist/src/runtime/emit/unary.js +125 -53
  151. package/dist/src/runtime/emit/unary.js.map +1 -1
  152. package/dist/src/runtime/emitters.d.ts +22 -0
  153. package/dist/src/runtime/emitters.d.ts.map +1 -1
  154. package/dist/src/runtime/emitters.js +29 -0
  155. package/dist/src/runtime/emitters.js.map +1 -1
  156. package/dist/src/runtime/scalar-fusion.d.ts +47 -0
  157. package/dist/src/runtime/scalar-fusion.d.ts.map +1 -0
  158. package/dist/src/runtime/scalar-fusion.js +275 -0
  159. package/dist/src/runtime/scalar-fusion.js.map +1 -0
  160. package/dist/src/runtime/strict-flags.d.ts +9 -0
  161. package/dist/src/runtime/strict-flags.d.ts.map +1 -1
  162. package/dist/src/runtime/strict-flags.js +9 -0
  163. package/dist/src/runtime/strict-flags.js.map +1 -1
  164. package/dist/src/runtime/strict-fork.js +2 -2
  165. package/dist/src/runtime/strict-fork.js.map +1 -1
  166. package/dist/src/runtime/strict-representation.d.ts +78 -0
  167. package/dist/src/runtime/strict-representation.d.ts.map +1 -0
  168. package/dist/src/runtime/strict-representation.js +159 -0
  169. package/dist/src/runtime/strict-representation.js.map +1 -0
  170. package/dist/src/schema/assertion.d.ts +58 -0
  171. package/dist/src/schema/assertion.d.ts.map +1 -1
  172. package/dist/src/schema/assertion.js +78 -0
  173. package/dist/src/schema/assertion.js.map +1 -1
  174. package/dist/src/schema/catalog-persistability.d.ts +11 -3
  175. package/dist/src/schema/catalog-persistability.d.ts.map +1 -1
  176. package/dist/src/schema/catalog-persistability.js +48 -29
  177. package/dist/src/schema/catalog-persistability.js.map +1 -1
  178. package/dist/src/schema/catalog.d.ts +22 -0
  179. package/dist/src/schema/catalog.d.ts.map +1 -1
  180. package/dist/src/schema/catalog.js +4 -1
  181. package/dist/src/schema/catalog.js.map +1 -1
  182. package/dist/src/schema/column-republication.d.ts +126 -0
  183. package/dist/src/schema/column-republication.d.ts.map +1 -0
  184. package/dist/src/schema/column-republication.js +121 -0
  185. package/dist/src/schema/column-republication.js.map +1 -0
  186. package/dist/src/schema/column-source-resolver.d.ts +29 -6
  187. package/dist/src/schema/column-source-resolver.d.ts.map +1 -1
  188. package/dist/src/schema/column-source-resolver.js +78 -9
  189. package/dist/src/schema/column-source-resolver.js.map +1 -1
  190. package/dist/src/schema/expression-dependents.d.ts +160 -0
  191. package/dist/src/schema/expression-dependents.d.ts.map +1 -0
  192. package/dist/src/schema/expression-dependents.js +228 -0
  193. package/dist/src/schema/expression-dependents.js.map +1 -0
  194. package/dist/src/schema/function.d.ts +15 -0
  195. package/dist/src/schema/function.d.ts.map +1 -1
  196. package/dist/src/schema/function.js.map +1 -1
  197. package/dist/src/schema/object-dependency-closure.d.ts +127 -0
  198. package/dist/src/schema/object-dependency-closure.d.ts.map +1 -0
  199. package/dist/src/schema/object-dependency-closure.js +117 -0
  200. package/dist/src/schema/object-dependency-closure.js.map +1 -0
  201. package/dist/src/schema/object-ref-resolver.d.ts +83 -0
  202. package/dist/src/schema/object-ref-resolver.d.ts.map +1 -0
  203. package/dist/src/schema/object-ref-resolver.js +135 -0
  204. package/dist/src/schema/object-ref-resolver.js.map +1 -0
  205. package/dist/src/schema/rename/column-rename.d.ts +228 -0
  206. package/dist/src/schema/rename/column-rename.d.ts.map +1 -0
  207. package/dist/src/schema/rename/column-rename.js +1225 -0
  208. package/dist/src/schema/rename/column-rename.js.map +1 -0
  209. package/dist/src/schema/rename/self-qualifier-strip.d.ts +29 -0
  210. package/dist/src/schema/rename/self-qualifier-strip.d.ts.map +1 -0
  211. package/dist/src/schema/rename/self-qualifier-strip.js +267 -0
  212. package/dist/src/schema/rename/self-qualifier-strip.js.map +1 -0
  213. package/dist/src/schema/rename/shared.d.ts +108 -0
  214. package/dist/src/schema/rename/shared.d.ts.map +1 -0
  215. package/dist/src/schema/rename/shared.js +49 -0
  216. package/dist/src/schema/rename/shared.js.map +1 -0
  217. package/dist/src/schema/rename/table-rename.d.ts +263 -0
  218. package/dist/src/schema/rename/table-rename.d.ts.map +1 -0
  219. package/dist/src/schema/rename/table-rename.js +860 -0
  220. package/dist/src/schema/rename/table-rename.js.map +1 -0
  221. package/dist/src/schema/rename-rewriter.d.ts +18 -278
  222. package/dist/src/schema/rename-rewriter.d.ts.map +1 -1
  223. package/dist/src/schema/rename-rewriter.js +17 -1506
  224. package/dist/src/schema/rename-rewriter.js.map +1 -1
  225. package/dist/src/schema/schema-differ.d.ts.map +1 -1
  226. package/dist/src/schema/schema-differ.js +228 -21
  227. package/dist/src/schema/schema-differ.js.map +1 -1
  228. package/dist/src/types/builtin-types.d.ts.map +1 -1
  229. package/dist/src/types/builtin-types.js +29 -36
  230. package/dist/src/types/builtin-types.js.map +1 -1
  231. package/dist/src/types/cast-semantics.d.ts +7 -5
  232. package/dist/src/types/cast-semantics.d.ts.map +1 -1
  233. package/dist/src/types/cast-semantics.js +20 -9
  234. package/dist/src/types/cast-semantics.js.map +1 -1
  235. package/dist/src/types/index.d.ts +1 -1
  236. package/dist/src/types/index.d.ts.map +1 -1
  237. package/dist/src/types/index.js +1 -1
  238. package/dist/src/types/index.js.map +1 -1
  239. package/dist/src/types/registry.d.ts.map +1 -1
  240. package/dist/src/types/registry.js +2 -1
  241. package/dist/src/types/registry.js.map +1 -1
  242. package/dist/src/types/temporal-ops.d.ts +119 -0
  243. package/dist/src/types/temporal-ops.d.ts.map +1 -0
  244. package/dist/src/types/temporal-ops.js +348 -0
  245. package/dist/src/types/temporal-ops.js.map +1 -0
  246. package/dist/src/types/temporal-types.d.ts +11 -0
  247. package/dist/src/types/temporal-types.d.ts.map +1 -1
  248. package/dist/src/types/temporal-types.js +87 -0
  249. package/dist/src/types/temporal-types.js.map +1 -1
  250. package/dist/src/util/affinity.d.ts +2 -1
  251. package/dist/src/util/affinity.d.ts.map +1 -1
  252. package/dist/src/util/affinity.js +16 -5
  253. package/dist/src/util/affinity.js.map +1 -1
  254. package/dist/src/util/ast-spine-clone.d.ts +2 -2
  255. package/dist/src/util/ast-spine-clone.js +2 -2
  256. package/dist/src/util/coercion.d.ts +22 -7
  257. package/dist/src/util/coercion.d.ts.map +1 -1
  258. package/dist/src/util/coercion.js +28 -15
  259. package/dist/src/util/coercion.js.map +1 -1
  260. package/dist/src/util/comparison.d.ts +25 -0
  261. package/dist/src/util/comparison.d.ts.map +1 -1
  262. package/dist/src/util/comparison.js +25 -0
  263. package/dist/src/util/comparison.js.map +1 -1
  264. package/dist/src/util/key-tuple-codec.d.ts +12 -3
  265. package/dist/src/util/key-tuple-codec.d.ts.map +1 -1
  266. package/dist/src/util/key-tuple-codec.js.map +1 -1
  267. package/dist/src/util/numeric-canonical.d.ts +26 -0
  268. package/dist/src/util/numeric-canonical.d.ts.map +1 -0
  269. package/dist/src/util/numeric-canonical.js +66 -0
  270. package/dist/src/util/numeric-canonical.js.map +1 -0
  271. package/dist/src/util/value-text.d.ts +48 -0
  272. package/dist/src/util/value-text.d.ts.map +1 -0
  273. package/dist/src/util/value-text.js +35 -0
  274. package/dist/src/util/value-text.js.map +1 -0
  275. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  276. package/dist/src/vtab/memory/layer/manager.js +14 -5
  277. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  278. package/dist/src/vtab/module.d.ts +25 -0
  279. package/dist/src/vtab/module.d.ts.map +1 -1
  280. package/package.json +4 -3
@@ -777,14 +777,30 @@ function hasApplicableConstraints(db, mt) {
777
777
  * the LIVE record here. So the live record is swapped for a constraint-stripped
778
778
  * clone for the duration of the scans (the ADD COLUMN intermediate-schema
779
779
  * discipline, see `runtime/emit/alter-table.ts`), then restored.
780
+ *
781
+ * `validationColumns` (the reshape arms only, {@link previewReshapedColumns})
782
+ * overrides the clone's column list with the attributes the reshape is ABOUT TO
783
+ * land, so a CHECK / FK resolves its affinity and collation from the final
784
+ * declared shape rather than the one being replaced. Comparison semantics are a
785
+ * function of the DECLARED column attributes, and the reshape's `retype` /
786
+ * `recollate` module ops run after this scan (they convert stored rows, so they
787
+ * must); without the override this scan would evaluate `v < '9'` on a column
788
+ * moving TEXT → INTEGER as a text comparison and admit a row that violates the
789
+ * constraint under the type it is about to have. Omitted (⇒ `mt.columns`) on
790
+ * every non-reshape path, so those stay byte-identical.
780
791
  */
781
- async function validateDeclaredConstraintsOverContents(db, mt) {
792
+ async function validateDeclaredConstraintsOverContents(db, mt, validationColumns) {
782
793
  const applicableChecks = mt.checkConstraints.filter(c => (c.operations & (RowOpFlag.INSERT | RowOpFlag.UPDATE)) !== 0);
783
794
  const fks = mt.foreignKeys ?? [];
784
795
  if (applicableChecks.length === 0 && fks.length === 0)
785
796
  return;
786
797
  const schema = db.schemaManager.getSchemaOrFail(mt.schemaName);
787
- const stripped = { ...mt, checkConstraints: Object.freeze([]), foreignKeys: undefined };
798
+ const stripped = {
799
+ ...mt,
800
+ columns: validationColumns ?? mt.columns,
801
+ checkConstraints: Object.freeze([]),
802
+ foreignKeys: undefined,
803
+ };
788
804
  schema.addTable(stripped);
789
805
  try {
790
806
  await validateChecksOverExistingRows(db, mt, applicableChecks, (check, exprSql) => maintainedTableCheckViolationError(mt.schemaName, mt.name, check.name ?? `_check_${mt.checkConstraints.indexOf(check)}`, exprSql));
@@ -1079,8 +1095,11 @@ discardBackingOnFailure = false) {
1079
1095
  changes = await host.applyMaintenance(conn, [{ kind: 'replace-all', rows }]);
1080
1096
  // Declared CHECK / child-side FK over the reconciled (derived) row set —
1081
1097
  // inside this try so a violation restores the prior record; the pending
1082
- // reconcile writes roll back with the failing statement.
1083
- await validateDeclaredConstraintsOverContents(db, live);
1098
+ // reconcile writes roll back with the failing statement. On the reshape arm
1099
+ // the scan resolves against the attributes the post-reconcile ops below are
1100
+ // about to land, keeping this path identical to the refresh reshape arm
1101
+ // (`reshapeBackingInPlace` → `rebuildBacking`).
1102
+ await validateDeclaredConstraintsOverContents(db, live, reshapePlan ? previewReshapedColumns(live, shape) : undefined);
1084
1103
  if (reshapePlan && reshapePlan.postReconcileOps.length > 0) {
1085
1104
  // Data-validating attribute ops (retype / recollate / tighten NOT NULL)
1086
1105
  // must validate the RECONCILED body rows, not the stale backing — but the
@@ -1320,8 +1339,14 @@ export async function createMaintainedTable(db, stmt) {
1320
1339
  * behavior. The caller is responsible for staleness re-validation when relevant;
1321
1340
  * this helper assumes the derivation body plans. Throws if the table is missing
1322
1341
  * from the catalog.
1342
+ *
1343
+ * `validationColumns` is the reshape arm's column preview
1344
+ * ({@link previewReshapedColumns}) — the type/collation attributes the reshape's
1345
+ * still-pending post-reconcile ops are about to land — forwarded to the scan so
1346
+ * the CHECK / FK resolve against the final declared shape. `undefined` on every
1347
+ * other path (and on a reshape that shifts neither attribute).
1323
1348
  */
1324
- export async function rebuildBacking(db, mv) {
1349
+ export async function rebuildBacking(db, mv, validationColumns) {
1325
1350
  const bodySql = astToString(mv.derivation.selectAst);
1326
1351
  const rows = await collectBodyRows(db, mv.schemaName, bodySql);
1327
1352
  const backing = db.schemaManager.getTable(mv.schemaName, mv.name);
@@ -1367,23 +1392,15 @@ export async function rebuildBacking(db, mv) {
1367
1392
  // leaving the pre-refresh committed contents intact (the MV stays stale, so the
1368
1393
  // next read re-validates rather than serving the rejected set).
1369
1394
  //
1370
- // Documented limitation (collation-sensitive CHECK on the reshape arm): on the
1371
- // reshape path this scan validates the rows in their PRE-recollate physical form
1372
- // — the catalog column still carries the OLD collation here, and any
1373
- // `recollate` op runs post-reconcile in reshapeBackingInPlace, AFTER this commit.
1374
- // So a CHECK whose truth flips under a recollate-during-reshape (e.g. `v <> 'abc'`
1375
- // with v recollated BINARY → NOCASE over a row 'ABC') passes here and is then
1376
- // recollated into a violating state. The same class of corner applies to a
1377
- // `retype` op (it shares this `postReconcileOps` batch): a CHECK whose truth flips
1378
- // under the column's NEW affinity (e.g. `v < '9'` retyped TEXT → INTEGER over a
1379
- // row '10' — lexicographic-true then numeric-false) passes here and is retyped into
1380
- // violation. Not closed: this commit is load-bearing (commit-first parity + the
1381
- // post-reconcile ops scan committed contents), and the attach reshape path uses the
1382
- // identical ordering. See docs/materialized-views.md § REFRESH MATERIALIZED VIEW
1383
- // "Known limitation — collation-sensitive CHECK" / "… type-sensitive CHECK" and
1384
- // maintained-table-refresh-revalidation.spec.ts § "reshape arm: collation-
1385
- // sensitive CHECK" / "reshape arm: type-sensitive CHECK".
1386
- await validateDeclaredConstraintsOverContents(db, backing);
1395
+ // On the reshape arm `validationColumns` carries the attributes the reshape is
1396
+ // about to land ({@link previewReshapedColumns}), so a CHECK / FK is evaluated
1397
+ // under the column's FINAL type and collation even though the `retype` /
1398
+ // `recollate` module ops still run post-reconcile in reshapeBackingInPlace. That
1399
+ // keeps this commit's ordering exactly as it was — the scan stays before the
1400
+ // commit, the post-reconcile ops still scan committed contents — while removing
1401
+ // the wrong-semantics gap. The attach reshape path passes the same preview at its
1402
+ // own call site, so both arms reject identically.
1403
+ await validateDeclaredConstraintsOverContents(db, backing, validationColumns);
1387
1404
  await conn.commit();
1388
1405
  }
1389
1406
  /**
@@ -2111,6 +2128,76 @@ function reshapeOpToChange(op) {
2111
2128
  function graftReshapedRecord(moduleSchema, source) {
2112
2129
  return { ...moduleSchema, derivation: source.derivation, tags: source.tags };
2113
2130
  }
2131
+ /**
2132
+ * The column list a reshape is ABOUT TO land, for the declared-constraint scan that
2133
+ * runs mid-reshape ({@link validateDeclaredConstraintsOverContents}).
2134
+ *
2135
+ * A reshape's data-validating ops (`retype` / `recollate`) must run AFTER the data
2136
+ * reconcile — they convert/re-key STORED rows, so running them first would validate
2137
+ * the about-to-be-discarded contents and throw spuriously. But a SQL comparison
2138
+ * takes its type affinity and its collation from the column's DECLARED attributes,
2139
+ * so a scan against the live (pre-op) record evaluates a declared CHECK under the
2140
+ * attributes the reshape is replacing: `check (v < '9')` on a column moving
2141
+ * TEXT → INTEGER compares as text ('10' < '9' is true) and never as the numeric
2142
+ * comparison it is becoming. Previewing the attributes fixes the semantics without
2143
+ * moving a single op — the scan stays exactly where it was, still before the commit.
2144
+ *
2145
+ * Maps `live`'s columns onto `shape`'s **by name** (names and order already agree:
2146
+ * the reshape's pre-reconcile batch has applied every rename / add / drop before
2147
+ * either caller reaches this) and overrides only `logicalType` and `collation`.
2148
+ * Returns `undefined` when neither attribute shifts, so a reshape with no
2149
+ * `retype`/`recollate` — and every non-reshape path — behaves exactly as before.
2150
+ *
2151
+ * Deliberately NOT previewed:
2152
+ * - **`notNull`.** The tighten-NOT-NULL op stays a post-reconcile module op and
2153
+ * keeps validating there. Declaring `notNull` early would let the optimizer fold
2154
+ * a nullability-sensitive CHECK into a vacuous pass — the same class of unsound
2155
+ * folding the caller's constraint-stripped-clone swap exists to prevent.
2156
+ * - **`defaultValue` and the generated-column attributes.** A reshape never moves
2157
+ * them, so previewing them could only introduce drift.
2158
+ *
2159
+ * Physical-PK columns need no special handling: `describePhysicalPkChange` refuses
2160
+ * a reshape whose key column changes type or collation, so a previewed attribute
2161
+ * can never desynchronize the key encoding `assertRefreshRowsAreSet` or the host's
2162
+ * keyed diff rely on.
2163
+ *
2164
+ * NOTE: the scan sees the rebuilt values in their PRE-conversion physical form but
2165
+ * under the POST-conversion declared type. These agree in practice — the target
2166
+ * attribute is derived FROM the body's own output type, so the body already emits
2167
+ * values of the new type. A retype whose conversion genuinely rewrites the value
2168
+ * (a text → date canonicalization turning '2024-06-05T00:00:00Z' into '2024-06-05')
2169
+ * would have the CHECK see the un-normalized spelling. Not chased; revisit if a
2170
+ * value-rewriting conversion is ever added to the reshape's op set.
2171
+ *
2172
+ * NOTE: with the preview in place, a body emitting a value that does not conform to
2173
+ * its own declared output type now trips the physical-representation checker
2174
+ * (`QUEREUS_REPR_STRICT`) at this scan rather than sliding through. That is a
2175
+ * genuine defect surfacing at the earliest honest point, not a regression.
2176
+ *
2177
+ * NOTE: this RE-DERIVES the attribute shift from live-vs-shape rather than reading
2178
+ * `ReshapePlan.postReconcileOps`, which is the authoritative list of the `retype` /
2179
+ * `recollate` ops that will actually run. The two agree today because the
2180
+ * pre-reconcile structural ops preserve attributes exactly ({@link backingColumnDef}
2181
+ * carries type + collation through a rename, and an `add` lands the shape column's
2182
+ * own attributes), so every live-vs-shape shift has a queued op and vice versa. If a
2183
+ * structural op ever stops preserving an attribute, this would preview an attribute
2184
+ * no op lands and the scan would reject rows the finished reshape accepts — build the
2185
+ * preview from `postReconcileOps` then.
2186
+ */
2187
+ function previewReshapedColumns(live, shape) {
2188
+ const byName = new Map(shape.columns.map(c => [c.name.toLowerCase(), c]));
2189
+ let shifted = false;
2190
+ const preview = live.columns.map(col => {
2191
+ const target = byName.get(col.name.toLowerCase());
2192
+ if (!target)
2193
+ return col;
2194
+ if (backingTypeMatches(col, target) && backingCollationMatches(col, target))
2195
+ return col;
2196
+ shifted = true;
2197
+ return { ...col, logicalType: target.logicalType, collation: target.collation };
2198
+ });
2199
+ return shifted ? Object.freeze(preview) : undefined;
2200
+ }
2114
2201
  /**
2115
2202
  * The sited error a refresh raises when the re-derived body shape cannot be
2116
2203
  * reconciled onto the live maintained table in place — an interleaving column
@@ -2209,8 +2296,10 @@ async function reshapeBackingInPlace(db, mv, shape, plan) {
2209
2296
  let live = graftReshapedRecord(current, mv);
2210
2297
  schema.addTable(live);
2211
2298
  // Data reconcile: re-run the body and swap contents (the identity-preserving
2212
- // data-only path — same host, same incarnation).
2213
- await rebuildBacking(db, live);
2299
+ // data-only path — same host, same incarnation). The column preview lets that
2300
+ // path's declared-constraint scan resolve against the type/collation the
2301
+ // post-reconcile ops below will land, not the ones they replace.
2302
+ await rebuildBacking(db, live, previewReshapedColumns(live, shape));
2214
2303
  // Post-reconcile data-validating ops (retype / recollate / tighten NOT NULL): the
2215
2304
  // reconciled body rows satisfy the new attribute where the discarded backing
2216
2305
  // might not, so each validates the fresh data, not the stale rows. Re-register
@@ -2221,14 +2310,14 @@ async function reshapeBackingInPlace(db, mv, shape, plan) {
2221
2310
  // partial throw. Per-op registration keeps the catalog tracking the module so a
2222
2311
  // mid-batch failure leaves a coherent, re-runnable table.
2223
2312
  //
2224
- // NOTE: a `recollate` here applies AFTER step 3's rebuildBacking has already
2225
- // validated + committed the rows under the OLD collation — so a collation-
2226
- // sensitive declared CHECK whose truth flips under this recollate is not caught
2227
- // by that scan. A `retype` in this same batch is the affinity analog: a CHECK
2228
- // whose truth flips under the column's NEW logical type (e.g. `v < '9'` retyped
2229
- // TEXT → INTEGER) is likewise validated under the OLD type and missed (documented
2230
- // limitation; see the note in rebuildBacking's constraint-bearing branch and
2231
- // docs/materialized-views.md § REFRESH MATERIALIZED VIEW).
2313
+ // These ops still run after step 3's rebuildBacking has validated + committed,
2314
+ // but the declared-CHECK/FK scan inside that step is no longer blind to them:
2315
+ // the `previewReshapedColumns` argument above hands it the type/collation each
2316
+ // `retype` / `recollate` here is about to land, so a constraint whose truth
2317
+ // flips under the new attribute (`v <> 'abc'` recollated BINARY → NOCASE over
2318
+ // 'ABC'; `v < '9'` retyped TEXT → INTEGER over '10') is rejected there, before
2319
+ // the commit, with nothing written. A tighten-NOT-NULL is deliberately NOT
2320
+ // previewed and keeps validating right here — see previewReshapedColumns.
2232
2321
  for (const op of plan.postReconcileOps) {
2233
2322
  current = await module.alterTable(db, mv.schemaName, mv.name, reshapeOpToChange(op));
2234
2323
  live = graftReshapedRecord(current, mv);
@@ -2393,8 +2482,9 @@ function maintainedTablesOf(schema) {
2393
2482
  /**
2394
2483
  * Rewrites every dependent materialized view in `schema` after a source TABLE
2395
2484
  * RENAME — the MV mirror of the plain-view loop in `propagateTableRenameInSchema`
2396
- * ("MV ≡ faster view"): the caller applies the same same-schema gate, and the body
2397
- * `selectAst` is mutated in place by the same `renameTableInAst` walker. An MV is
2485
+ * ("MV ≡ faster view"): the caller calls this once per schema in the catalog with
2486
+ * `target` bound to THAT schema's home path, and the body `selectAst` is mutated
2487
+ * in place by the same `renameTableInAst` walker. An MV is
2398
2488
  * processed when its body AST changed, its `insert defaults` clause changed (an
2399
2489
  * expr subquery can name the renamed table even when the body doesn't), OR its
2400
2490
  * `sourceTables` carries the old base — the latter catches a body that reads the
@@ -2409,8 +2499,9 @@ function maintainedTablesOf(schema) {
2409
2499
  * `materialized_view_modified`. Failures mark the MV stale and propagation
2410
2500
  * continues — best-effort, like the rest of the rename propagation.
2411
2501
  */
2412
- export async function propagateTableRenameToMaterializedViews(db, schema, renamedSchemaName, oldName, newName, preStale) {
2413
- const schemaLower = renamedSchemaName.toLowerCase();
2502
+ export async function propagateTableRenameToMaterializedViews(db, schema, preStale, target) {
2503
+ const { oldName, newName } = target;
2504
+ const schemaLower = target.schemaName.toLowerCase();
2414
2505
  const oldBase = `${schemaLower}.${oldName.toLowerCase()}`;
2415
2506
  const newBase = `${schemaLower}.${newName.toLowerCase()}`;
2416
2507
  for (const mv of maintainedTablesOf(schema)) {
@@ -2419,7 +2510,7 @@ export async function propagateTableRenameToMaterializedViews(db, schema, rename
2419
2510
  // The body walk also descends the trailing `with defaults (…)` clause
2420
2511
  // (now on `selectAst.defaults`), so a defaults-expr subquery naming the
2421
2512
  // renamed table flips `bodyChanged` even when the body never names it.
2422
- const bodyChanged = renameTableInAst(d.selectAst, oldName, newName, renamedSchemaName);
2513
+ const bodyChanged = renameTableInAst(d.selectAst, target);
2423
2514
  if (!bodyChanged && !d.sourceTables.includes(oldBase))
2424
2515
  continue;
2425
2516
  const covers = d.covers
@@ -2440,7 +2531,10 @@ export async function propagateTableRenameToMaterializedViews(db, schema, rename
2440
2531
  /**
2441
2532
  * Rewrites every dependent materialized view in `schema` after a source COLUMN
2442
2533
  * RENAME — the MV mirror of the plain-view loop in `propagateColumnRenameInSchema`
2443
- * (same same-schema gate at the caller, same in-place `renameColumnInAst` walk).
2534
+ * (called once per schema PER CASCADE ROUND — the target may be the renamed table
2535
+ * or a view/MV whose published names a prior round shifted, see
2536
+ * `column-rename-cascade.ts` — with that schema's resolver, same in-place
2537
+ * `renameColumnInAst` walk).
2444
2538
  * The body walk also descends the trailing `with defaults (…)` clause (now on
2445
2539
  * `selectAst.defaults`): the clause target is typically a projected-away NOT NULL
2446
2540
  * column the body never mentions, so its rewrite still flips `bodyChanged` and
@@ -2452,14 +2546,14 @@ export async function propagateTableRenameToMaterializedViews(db, schema, rename
2452
2546
  * (a bare passthrough projection of the renamed column — plain-view parity),
2453
2547
  * which {@link applyMaterializedViewRewrite} carries onto the live backing table.
2454
2548
  */
2455
- export async function propagateColumnRenameToMaterializedViews(db, schema, renamedSchemaName, tableName, oldCol, newCol, preStale, resolveColumnInSource) {
2549
+ export async function propagateColumnRenameToMaterializedViews(db, schema, tableName, oldCol, newCol, preStale, resolve, targetKey, resolveColumnInSource) {
2456
2550
  for (const mv of maintainedTablesOf(schema)) {
2457
2551
  try {
2458
2552
  const d = mv.derivation;
2459
2553
  // `resolveColumnInSource` keeps the body walk scope-aware for a defaults-expr
2460
2554
  // subquery referencing a like-named column on its own FROM — plain-view /
2461
2555
  // differ-reconcile parity (see `renameColumnInAst`).
2462
- const bodyChanged = renameColumnInAst(d.selectAst, tableName, oldCol, newCol, renamedSchemaName, resolveColumnInSource);
2556
+ const bodyChanged = renameColumnInAst(d.selectAst, tableName, oldCol, newCol, resolve, targetKey, 'none', resolveColumnInSource);
2463
2557
  if (!bodyChanged)
2464
2558
  continue;
2465
2559
  await applyMaterializedViewRewrite(db, schema, mv, {}, preStale, /*renamedColumns*/ true);
@@ -2580,10 +2674,22 @@ async function restoreMaterializedViewLive(db, schema, mv, backingNames) {
2580
2674
  * sql, sourceTables) is unchanged here — `stale` is runtime state, not persisted.
2581
2675
  * Walks all schemas (the listener marks cross-schema dependents too), in creation
2582
2676
  * order — topological for same-schema MV chains, so a producer restores before its
2583
- * consumer is examined. A chained MV whose body references a renamed-away producer
2584
- * output name fails shape derivation and stays stale (staleness-diagnostic parity
2585
- * with a broken plain-view chain). Best-effort like the rest of the propagation:
2586
- * a per-MV failure logs, leaves that MV stale, and continues.
2677
+ * consumer is examined. A chained MV normally follows a producer's shifted output
2678
+ * name through the cascade driver's later rounds (`column-rename-cascade.ts`); one
2679
+ * whose body still references a renamed-away name (a mid-statement rewrite
2680
+ * failure) fails shape derivation here and stays stale.
2681
+ *
2682
+ * NOTE: the walk is schema-by-schema, then creation order WITHIN a schema, so a
2683
+ * CROSS-schema MV chain is only topological when the producer's schema is iterated
2684
+ * first. Harmless today — a consumer whose body does not itself name the renamed
2685
+ * object is skipped by the propagation entirely and only ever reaches this pass, and
2686
+ * a producer whose own NAME did not change re-plans fine either way (verified for
2687
+ * both verbs in `test/schema/rename-cross-schema.spec.ts`). If a producer's output
2688
+ * names can shift while its consumer lives in an earlier-iterated schema, this pass
2689
+ * needs a topological order (or a second round) rather than catalog order.
2690
+ *
2691
+ * Best-effort like the rest of the propagation: a per-MV failure logs, leaves that MV
2692
+ * stale, and continues.
2587
2693
  *
2588
2694
  * NOTE: firing no `materialized_view_modified` is deliberate, but
2589
2695
  * {@link renameShiftedBackingColumns} (run from the shared restore tail) DOES change the
@@ -2653,11 +2759,14 @@ function sameSourceTables(a, b) {
2653
2759
  * difference (count / types / PK) is NOT a rename outcome — throw so the caller's
2654
2760
  * failure path leaves the MV stale rather than rebuilding data here.
2655
2761
  *
2656
- * The backing `table_modified` fired on a real rename deliberately cascades: a
2657
- * chained MV whose body references the OLD output name is marked stale by the
2658
- * manager's listener and surfaces the staleness diagnostic on its next read
2659
- * (parity with a broken plain-view chain — strictly better than silently freezing),
2660
- * and cached plans scanning the backing directly recompile against the new names.
2762
+ * The backing `table_modified` fired on a real rename deliberately cascades to
2763
+ * the manager's listener (a chained MV referencing the OLD output name is marked
2764
+ * stale), and cached plans scanning the backing directly recompile against the
2765
+ * new names. Within a RENAME COLUMN statement that staleness is transient: the
2766
+ * cascade driver (`column-rename-cascade.ts`) re-runs the propagation with this
2767
+ * MV as the target, so the chained body is rewritten and restored in a later
2768
+ * round — the staleness diagnostic remains only for a body the cascade could not
2769
+ * rewrite (a mid-statement failure).
2661
2770
  */
2662
2771
  async function renameShiftedBackingColumns(db, schema, mv, bodySql, preDerivedShape) {
2663
2772
  const shape = preDerivedShape ?? deriveBackingShape(db, mv.schemaName, bodySql, mv.derivation.columns);