@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
@@ -0,0 +1,860 @@
1
+ import { eq, objectRefKey, objectRefKeySchema, rewriteEach } from './shared.js';
2
+ /**
3
+ * `target.resolve` and the derived `targetKey` (`objectRefKey(target.schemaName,
4
+ * target.oldName)`) decide matching for the rewrite and the probe below alike: a
5
+ * reference matches when `resolve(ref.schema, ref.name)` — the reference's
6
+ * planner-parity resolution under the WALKED BODY's home schema path — equals
7
+ * `targetKey`. The bare-name equality check in front is a pure short-circuit:
8
+ * the resolver echoes the name it is given into the key, so a reference spelled
9
+ * differently can never resolve to the target.
10
+ *
11
+ * The rewrite additionally enforces a POST-CONDITION the probe does not need,
12
+ * and it covers EVERY reference the walk reports — not only the ones it
13
+ * rewrites:
14
+ *
15
+ * > Walking a body for a rename, every reference must mean after the statement
16
+ * > exactly what it meant before.
17
+ *
18
+ * Both arms decide that the same way: re-resolve the reference under the same
19
+ * home schema path against the catalog AS IT WILL BE AFTER THE RENAME
20
+ * (`target.resolveAfter`) and compare with what it meant before.
21
+ *
22
+ * - A REWRITTEN reference must still yield the renamed object's key. When it
23
+ * would not — the bare new name is captured by an earlier schema on the
24
+ * body's home path — it is schema-qualified to the renamed schema via
25
+ * {@link TableRef.qualify}.
26
+ * - An UNTOUCHED reference must still yield its own before-answer. A rename
27
+ * also CREATES a name, and that new name can capture a reference the walk
28
+ * never matched: a `temp`-owned body reading bare `k` (falling through to
29
+ * `main.k`, because `temp` holds no `k`) silently re-binds to `temp.k` the
30
+ * moment `alter table temp.other rename to k` lands, without its text ever
31
+ * mentioning the renamed table. When the answer would change, the reference
32
+ * is qualified to the schema its BEFORE-answer named — recovered from that
33
+ * key by {@link import('./shared.js').objectRefKeySchema}. This arm applies
34
+ * to the stored bodies that plan under the home schema path and is walked
35
+ * ONCE per body; {@link TableRenameOpts.schemaAuthoredBody} turns it off for
36
+ * the schema-authored expressions, which need it neither for correctness nor
37
+ * for the re-walks they are deliberately subjected to — see that flag.
38
+ *
39
+ * The post-condition also covers the FROM-frame namespace, not just the
40
+ * catalog's: inside one body, the bare qualifier an unaliased FROM source
41
+ * exposes must keep binding that source. When the rename would give a source a
42
+ * name already visible as a qualifier where it sits ({@link
43
+ * TableRef.qualifierCollides}), the source pins its pre-rename spelling as an
44
+ * explicit alias ({@link TableRef.aliasAs}) and every column qualifier bound
45
+ * through it keeps the old spelling — `from t join u as t2` becomes
46
+ * `from t2 as t join u as t2` under `t → t2`, with `t.x` untouched. And when
47
+ * the new name is shadowed by a CTE in scope at the source ({@link
48
+ * TableRef.cteShadows}) — invisible to the catalog resolvers — the reference
49
+ * is schema-qualified so it cannot re-bind to the CTE.
50
+ *
51
+ * Qualification is conditional in both arms, never eager, so the common
52
+ * no-collision rename leaves body text (and a materialized view's `bodyHash`)
53
+ * exactly as before. A qualified reference resolves by passthrough, so its
54
+ * before- and after-answers are always equal and neither arm can fire on one;
55
+ * only unqualified references ever gain a qualifier. And only the NEW name can
56
+ * change meaning without being rewritten: removing the old name can only push a
57
+ * resolution later, and the references that resolved to the removed entry are
58
+ * exactly the ones the rewrite already matches — so there is no freed-name
59
+ * direction to handle.
60
+ *
61
+ * ALREADY-BROKEN BODIES: the resolver answers a total function — a name held by
62
+ * no schema on the path still gets a stable key, the home schema's — so a body
63
+ * naming an object that exists nowhere reads `before = <home>.<name>`, and a
64
+ * rename introducing that name in an earlier schema flips `after`. The
65
+ * untouched arm then qualifies the reference to the home schema, PINNING the
66
+ * pre-existing "no such table" failure rather than letting the body silently
67
+ * start reading the new arrival. That is the invariant-faithful answer, so no
68
+ * existence probe is added to dodge it (same reasoning as the seedless-qualifier
69
+ * emit site below: it only ever fires on an already-unevaluable body).
70
+ */
71
+ export function renameTableInAst(node, target, opts) {
72
+ if (!node)
73
+ return false;
74
+ const { oldName, newName, schemaName, resolve, resolveAfter } = target;
75
+ const targetKey = objectRefKey(schemaName, oldName);
76
+ const newTargetKey = objectRefKey(schemaName, newName);
77
+ let changed = false;
78
+ walkTableRefs(node, ref => {
79
+ if (eq(ref.name, oldName) && resolve(ref.schema, ref.name) === targetKey) {
80
+ // Qualifier-namespace guard, the FROM-frame twin of the catalog
81
+ // post-condition below: the bare qualifier an unaliased source
82
+ // exposes must keep binding that source. When the new name is
83
+ // already visible as a qualifier where the source sits, the source
84
+ // takes the new name but pins the OLD spelling as an explicit
85
+ // alias, and every qualifier bound through it keeps that spelling.
86
+ // Guarded on a real name change so a case-only rename never
87
+ // self-collides on the source's own frame entry.
88
+ //
89
+ // NOTE: deliberately conservative — the source is aliased whenever
90
+ // the new name is visible in scope, even when nothing in its
91
+ // subtree actually spells it. Detecting real use would need a
92
+ // second pass over the subtree; the extra alias is harmless and
93
+ // only appears in a genuine collision. It is not free for a
94
+ // MAINTAINED body, though: a pin changes the body text, hence the
95
+ // `bodyHash`, hence forces a re-hash / regenerate on an MV whose
96
+ // meaning did not change. If that ever shows up as churn on large
97
+ // bodies, narrow the predicate to names the subtree actually
98
+ // spells as a qualifier.
99
+ const collides = !eq(oldName, newName) && (ref.qualifierCollides?.(newName) ?? false);
100
+ if (collides && !ref.aliasAs) {
101
+ // A column qualifier bound to a source the rename is about to
102
+ // alias: the aliased source keeps exposing the old spelling,
103
+ // so the qualifier keeps it too. The source's own emit (same
104
+ // walk, same predicate) is what sets `changed`.
105
+ return;
106
+ }
107
+ ref.setName(newName);
108
+ changed = true;
109
+ if (collides)
110
+ ref.aliasAs?.(oldName);
111
+ // Catalog post-condition — with one addition the catalog resolvers
112
+ // cannot express: a CTE in scope at the source captures a bare
113
+ // name before the catalog is ever consulted, so a rewritten
114
+ // reference whose new name a CTE shadows must be schema-qualified
115
+ // even when the catalog answer alone would leave it bare.
116
+ if (ref.qualify && (resolveAfter(ref.schema, newName) !== newTargetKey || (ref.cteShadows?.(newName) ?? false))) {
117
+ ref.qualify(schemaName);
118
+ }
119
+ return;
120
+ }
121
+ // The untouched arm (see the doc comment). Only a reference that
122
+ // re-resolves through the catalog carries `qualify` — the rest bind
123
+ // through a FROM frame and are preserved by qualifying their source.
124
+ if (opts?.schemaAuthoredBody || !ref.qualify)
125
+ return;
126
+ // NOTE: asks the resolvers about EVERY reference, where the rewrite arm
127
+ // above short-circuits on a bare-name compare first. The arm can in fact
128
+ // only fire on a reference spelling `newName` — the two resolvers differ
129
+ // only over `schemaName`'s name set, and the `oldName` direction is either
130
+ // the rewrite arm's or unchanged — so an `eq(ref.name, newName)` guard here
131
+ // would be equivalent and cheaper. Declined: it trades two Set lookups per
132
+ // reference on a DDL-only path for a claim that silently loses coverage if
133
+ // the `resolve`/`resolveAfter` pair ever differs more broadly than one
134
+ // table rename. Add the guard if rename propagation over a schema-heavy
135
+ // catalog ever measures hot.
136
+ const before = resolve(ref.schema, ref.name);
137
+ if (before === undefined || before === resolveAfter(ref.schema, ref.name))
138
+ return;
139
+ ref.qualify(objectRefKeySchema(before, ref.name.toLowerCase()));
140
+ changed = true;
141
+ }, opts);
142
+ return changed;
143
+ }
144
+ /**
145
+ * Whether `node` refers to the table/view identified by `targetKey` (spelled
146
+ * `name`) — read-only, nothing is mutated.
147
+ *
148
+ * Deliberately the SAME traversal {@link renameTableInAst} uses — both are
149
+ * sinks over {@link visitTableRefs} — so "refers to" can never drift from
150
+ * "would have been rewritten by a rename". That equivalence is the whole
151
+ * point: the DROP guard refuses exactly the cases `ALTER TABLE … RENAME`
152
+ * would have followed. In particular, a body whose `with <name> as (…)`
153
+ * merely SHADOWS the probed name is not a reference — the walk skips it for
154
+ * both verbs. The probe's sink stops the walk at the first match.
155
+ *
156
+ * The column-level probes ({@link import('./column-rename.js').columnReferencedInAst},
157
+ * {@link import('./column-rename.js').columnReferencedInCheckExpression}) reach
158
+ * the same equivalence a different way — a real rename, to a sentinel name,
159
+ * over a throwaway clone — because the column walker has ~8 mutation points
160
+ * and a CTE-re-exposure branch that reads the new name; see their comments.
161
+ */
162
+ export function tableReferencedInAst(node, name, resolve, targetKey, opts) {
163
+ if (!node)
164
+ return false;
165
+ let found = false;
166
+ walkTableRefs(node, ref => {
167
+ if (eq(ref.name, name) && resolve(ref.schema, ref.name) === targetKey) {
168
+ found = true;
169
+ return true;
170
+ }
171
+ }, opts);
172
+ return found;
173
+ }
174
+ /**
175
+ * Every real (non-shadowed) table / view reference in `node`, keyed the way
176
+ * {@link renameTableInAst} and {@link tableReferencedInAst} key their target:
177
+ * `resolve(ref.schema, ref.name)`, the reference's planner-parity resolution
178
+ * under the WALKED BODY's home schema path.
179
+ *
180
+ * The collect-all THIRD sink over the same {@link walkTableRefs} traversal, so
181
+ * it inherits the scope-awareness of the other two for free: a body whose
182
+ * `with t as (…)` merely SHADOWS the name contributes no `<schema>.t` key, a FROM
183
+ * alias contributes nothing, and a `new.` / `old.` row-image qualifier under
184
+ * {@link TableRenameOpts.rowImageContext} contributes nothing. That matters
185
+ * more here than anywhere else — a collect-everything walk is exactly where
186
+ * that property gets quietly lost, and the reachability closure built on this
187
+ * ({@link import('../object-dependency-closure.js').reachableObjects}) turns
188
+ * every key it yields into a refused DROP.
189
+ *
190
+ * The value is the object NAME the key was built from, lowercased. The
191
+ * resolver echoes the name it is given into the key, so this is always
192
+ * `ref.name.toLowerCase()`; it is returned rather than re-derived because a
193
+ * schema name may itself contain a dot, which makes splitting a key by
194
+ * separator scan wrong — see {@link import('./shared.js').objectRefKeySchema},
195
+ * whose whole job is that split and which needs exactly this.
196
+ */
197
+ export function collectTableRefsInAst(node, resolve, opts) {
198
+ const refs = new Map();
199
+ if (!node)
200
+ return refs;
201
+ walkTableRefs(node, ref => {
202
+ const key = resolve(ref.schema, ref.name);
203
+ // `undefined` means "no resolver could be consulted at all" — a reference
204
+ // with no key is not something a closure can follow.
205
+ if (key !== undefined)
206
+ refs.set(key, ref.name.toLowerCase());
207
+ }, opts);
208
+ return refs;
209
+ }
210
+ /**
211
+ * Rewrite the renamed table inside every partial-index predicate of `indexes`,
212
+ * in place. A predicate may carry a table-qualified self-reference
213
+ * (`create index ix on t (b) where t.b > 0`), which a table rename must follow.
214
+ *
215
+ * No {@link TableRenameOpts.rowImageContext}: a predicate describes rows
216
+ * already stored, so `new.x` there is a real table reference — see the flag's
217
+ * doc comment. {@link TableRenameOpts.schemaAuthoredBody} IS set: a predicate
218
+ * plans under its owning schema alone, and this AST is one of the several the
219
+ * rename walks more than once.
220
+ *
221
+ * Sharing and idempotence work exactly as in
222
+ * {@link import('./column-rename.js').renameColumnInIndexPredicates}: the
223
+ * predicate `Expression` is shared by reference with the catalog's
224
+ * `TableSchema` and with a unique partial index's `derivedFromIndex` UNIQUE
225
+ * constraint, so one in-place rewrite covers all of them, and a second call
226
+ * with the same pair finds nothing naming `oldName` and returns false.
227
+ */
228
+ export function renameTableInIndexPredicates(indexes, target) {
229
+ return rewriteEach(indexes, idx => idx.predicate, expr => renameTableInAst(expr, target, { schemaAuthoredBody: true }));
230
+ }
231
+ /**
232
+ * Rewrite the renamed table inside every CHECK constraint expression of `checks`,
233
+ * in place. A CHECK may carry a table-qualified self-reference (`check (t.b > 0)`)
234
+ * exactly as a partial-index predicate may, and a table rename must follow it.
235
+ *
236
+ * A CHECK is evaluated against a written row, so the walk runs with
237
+ * {@link TableRenameOpts.rowImageContext}: a bare `new.a` / `old.a` names the
238
+ * row image and survives even a rename of a table literally called `new`. It
239
+ * also runs with {@link TableRenameOpts.schemaAuthoredBody}, for the same
240
+ * reasons the predicate arm above does.
241
+ *
242
+ * Same sharing and idempotence story as {@link renameTableInIndexPredicates}: the
243
+ * `expr` is the very AST the catalog's `TableSchema` holds, so one rewrite covers
244
+ * every holder and a second call with the same pair is a no-op.
245
+ */
246
+ export function renameTableInCheckConstraints(checks, target) {
247
+ return rewriteEach(checks, cc => cc.expr, expr => renameTableInAst(expr, target, { rowImageContext: true, schemaAuthoredBody: true }));
248
+ }
249
+ /**
250
+ * Rewrite the renamed table inside the two expressions a `ColumnSchema` can carry —
251
+ * a column DEFAULT (`w integer default ((select min(v) from u))`, however authored:
252
+ * inline, or via `ALTER TABLE … ALTER COLUMN … SET DEFAULT`, which writes the same
253
+ * field) and a generated column's body (`g integer generated always as ((select
254
+ * min(u.v) from u) + id)`) — in place.
255
+ *
256
+ * Both expressions evaluate against the row being written, so the walk runs
257
+ * with {@link TableRenameOpts.rowImageContext}: a default's `new.a` names the
258
+ * row image, not a table called `new`. It also runs with
259
+ * {@link TableRenameOpts.schemaAuthoredBody}, for the same reasons the two arms
260
+ * above do.
261
+ *
262
+ * Unlike the column-rename counterpart
263
+ * ({@link import('./column-rename.js').renameColumnInColumnExpressions}) there
264
+ * is no seeded/unseeded split: {@link renameTableInAst} resolves nothing against an
265
+ * implicit owning table, so the SAME entry point is correct for the renamed table's own
266
+ * columns (a self-referencing default, `default ((select count(*) from t))`) and for
267
+ * every other table's.
268
+ *
269
+ * Same sharing and idempotence story as {@link renameTableInCheckConstraints}: the
270
+ * `Expression` is the very AST the catalog's `TableSchema` holds, so one in-place
271
+ * rewrite reaches every holder and a second call with the same pair finds nothing
272
+ * naming `oldName` and returns false.
273
+ *
274
+ * The parameter is structurally typed rather than `ColumnSchema[]` so this module stays
275
+ * free of catalog imports; `ColumnSchema` satisfies it.
276
+ */
277
+ export function renameTableInColumnExpressions(columns, target) {
278
+ const rewrite = (expr) => renameTableInAst(expr, target, { rowImageContext: true, schemaAuthoredBody: true });
279
+ // Both walks always run — `||` on the results, not short-circuited between them.
280
+ const defaultsChanged = rewriteEach(columns, c => c.defaultValue ?? undefined, rewrite);
281
+ const generatedChanged = rewriteEach(columns, c => c.generatedExpr, rewrite);
282
+ return defaultsChanged || generatedChanged;
283
+ }
284
+ // ──────────────────────────────────────────────────────────────────────
285
+ // The walk
286
+ // ──────────────────────────────────────────────────────────────────────
287
+ function walkTableRefs(node, sink, opts) {
288
+ const state = {
289
+ sink,
290
+ rowImage: opts?.rowImageContext ?? false,
291
+ stack: [],
292
+ stop: false,
293
+ };
294
+ visitTableRefs(node, state);
295
+ }
296
+ function emptyTableFrame() {
297
+ return { ctes: new Set(), bound: new Map() };
298
+ }
299
+ function emit(state, ref) {
300
+ if (state.stop)
301
+ return;
302
+ if (state.sink(ref) === true)
303
+ state.stop = true;
304
+ }
305
+ /** Whether any enclosing WITH frame declares `nameLower` as a CTE. */
306
+ function isCteInScope(state, nameLower) {
307
+ for (const frame of state.stack) {
308
+ if (frame.ctes.has(nameLower))
309
+ return true;
310
+ }
311
+ return false;
312
+ }
313
+ /**
314
+ * Resolve a bare column qualifier innermost-first against the scope stack.
315
+ * `binding` is the real unaliased table source it binds, or `null` when it
316
+ * binds something that is not directly a table name (an alias, a CTE, a
317
+ * subquery / function source); `frameIndex` is the stack index of the frame
318
+ * that bound it, so the collision predicate can be evaluated at the BINDING
319
+ * frame's depth — a deeper frame binding the new name is inner to the source
320
+ * and must not falsely trigger. Returns `undefined` when nothing in scope
321
+ * binds the qualifier.
322
+ */
323
+ function resolveQualifier(state, qualifierLower) {
324
+ for (let i = state.stack.length - 1; i >= 0; i--) {
325
+ const frame = state.stack[i];
326
+ const binding = frame.bound.get(qualifierLower);
327
+ if (binding !== undefined)
328
+ return { binding, frameIndex: i };
329
+ // A CTE name in scope shadows the qualifier even without a FROM entry
330
+ // (mirrors the column walker's rebind scan, which counts `ctesInScope`).
331
+ if (frame.ctes.has(qualifierLower))
332
+ return { binding: null, frameIndex: i };
333
+ }
334
+ return undefined;
335
+ }
336
+ /**
337
+ * Whether `nameLower` is visible as a column qualifier at frame `limit` or any
338
+ * enclosing frame — a FROM binding (an alias or an unaliased source's name) or
339
+ * a CTE declaration.
340
+ */
341
+ function qualifierVisibleUpTo(state, nameLower, limit) {
342
+ for (let i = 0; i <= limit && i < state.stack.length; i++) {
343
+ const frame = state.stack[i];
344
+ if (frame.bound.has(nameLower) || frame.ctes.has(nameLower))
345
+ return true;
346
+ }
347
+ return false;
348
+ }
349
+ /**
350
+ * The predicate behind {@link TableRef.qualifierCollides}, evaluated at the
351
+ * SOURCE's own frame (its FROM frame for the source emit, the binding frame
352
+ * for a bound column-qualifier emit — the same frame, so the two sites always
353
+ * agree). `nameLower` collides when it is visible as a qualifier at or above
354
+ * that frame, OR when the frame's select SUBTREE can introduce it (an inner
355
+ * alias / source / CTE): a qualifier bound to the source can sit inside a
356
+ * correlated subquery, where an inner binding of the new name would capture
357
+ * its new spelling — `select t.x from t where exists (select 1 from other as
358
+ * t2 where t2.id = t.id)` must not let `t → t2` re-bind the correlation.
359
+ * Frame state was filled with pre-rewrite names before anything under the
360
+ * FROM was visited, and the subtree set is memoized on first consult, so
361
+ * every consult for one frame gets the same answer regardless of visit order.
362
+ */
363
+ function qualifierCollidesAt(state, nameLower, frameIndex) {
364
+ if (qualifierVisibleUpTo(state, nameLower, frameIndex))
365
+ return true;
366
+ const frame = state.stack[frameIndex];
367
+ if (!frame?.subtreeRoot)
368
+ return false;
369
+ frame.introduced ??= collectIntroducedQualifierNames(frame.subtreeRoot);
370
+ return frame.introduced.has(nameLower);
371
+ }
372
+ /**
373
+ * Every name `root`'s subtree can bind as a column qualifier or capture a FROM
374
+ * source with, lowercased: FROM source bare names and aliases, subquery /
375
+ * function-source aliases, CTE names, UPDATE/DELETE correlation names.
376
+ * Deliberately position-blind and conservative — a name introduced in a
377
+ * sibling subquery that could never actually shadow the consulted source still
378
+ * counts, because the only cost of a false positive is a harmless explicit
379
+ * alias on the renamed source. Structural recursion over plain objects/arrays
380
+ * so unknown node kinds are walked rather than missed.
381
+ */
382
+ function collectIntroducedQualifierNames(root) {
383
+ const names = new Set();
384
+ const visit = (node) => {
385
+ if (Array.isArray(node)) {
386
+ for (const item of node)
387
+ visit(item);
388
+ return;
389
+ }
390
+ if (node === null || typeof node !== 'object')
391
+ return;
392
+ const obj = node;
393
+ switch (obj.type) {
394
+ case 'table': {
395
+ const ts = obj;
396
+ names.add((ts.alias ?? ts.table.name).toLowerCase());
397
+ break;
398
+ }
399
+ case 'subquerySource':
400
+ names.add(obj.alias.toLowerCase());
401
+ break;
402
+ case 'functionSource': {
403
+ const alias = obj.alias;
404
+ if (alias)
405
+ names.add(alias.toLowerCase());
406
+ break;
407
+ }
408
+ case 'commonTableExpr':
409
+ names.add(obj.name.toLowerCase());
410
+ break;
411
+ case 'update':
412
+ case 'delete': {
413
+ const alias = obj.alias;
414
+ if (alias)
415
+ names.add(alias.toLowerCase());
416
+ break;
417
+ }
418
+ default:
419
+ break;
420
+ }
421
+ for (const value of Object.values(obj))
422
+ visit(value);
423
+ };
424
+ visit(root);
425
+ return names;
426
+ }
427
+ /**
428
+ * Push a WITH frame and visit each member's body inside it, registering names
429
+ * in the SAME visibility order the planner uses
430
+ * ({@link import('../../planner/building/with.js').buildCommonTableExpr}) and
431
+ * the column walker mirrors: a `with recursive` member registers its own name
432
+ * BEFORE its body is visited (so the recursive leg's self-reference resolves
433
+ * to the CTE, not a same-named real table); a non-recursive member registers
434
+ * AFTER (its body must not see itself, only prior siblings — a forward
435
+ * reference to a later sibling binds the real table and still rewrites).
436
+ *
437
+ * Caller is responsible for popping the frame (in a `finally`).
438
+ */
439
+ function pushWithFrame(withClause, state) {
440
+ const frame = emptyTableFrame();
441
+ state.stack.push(frame);
442
+ if (!withClause)
443
+ return;
444
+ for (const cte of withClause.ctes) {
445
+ const nameLower = cte.name.toLowerCase();
446
+ if (withClause.recursive)
447
+ frame.ctes.add(nameLower);
448
+ visitTableRefs(cte.query, state);
449
+ frame.ctes.add(nameLower);
450
+ }
451
+ }
452
+ /**
453
+ * Collect the qualifiers a FROM clause binds into `frame`. Runs BEFORE the
454
+ * frame is pushed (and before anything under the FROM is visited), so the
455
+ * bindings reflect pre-rewrite names — every match still compares against the
456
+ * old name.
457
+ */
458
+ function collectFromBindings(item, state, frame) {
459
+ switch (item.type) {
460
+ case 'table': {
461
+ const ts = item;
462
+ const nameLower = ts.table.name.toLowerCase();
463
+ const bindsCte = ts.table.schema === undefined && isCteInScope(state, nameLower);
464
+ if (ts.alias) {
465
+ // The alias replaces the source name as the row's only qualifier;
466
+ // renaming a table never changes an alias, so qualified refs
467
+ // through it have nothing to rewrite even when the underlying
468
+ // source IS the renamed table (the FROM source itself is still
469
+ // reported as a reference by the visit below).
470
+ frame.bound.set(ts.alias.toLowerCase(), null);
471
+ }
472
+ else {
473
+ frame.bound.set(nameLower, bindsCte ? null : { schema: ts.table.schema, name: ts.table.name });
474
+ }
475
+ break;
476
+ }
477
+ case 'join': {
478
+ const join = item;
479
+ collectFromBindings(join.left, state, frame);
480
+ collectFromBindings(join.right, state, frame);
481
+ break;
482
+ }
483
+ case 'subquerySource':
484
+ frame.bound.set(item.alias.toLowerCase(), null);
485
+ break;
486
+ case 'functionSource': {
487
+ const fs = item;
488
+ // An unaliased function source contributes no qualifier.
489
+ if (fs.alias)
490
+ frame.bound.set(fs.alias.toLowerCase(), null);
491
+ break;
492
+ }
493
+ }
494
+ }
495
+ /**
496
+ * A DML target identifier. Mirrors the planner's write-target rule
497
+ * ({@link import('../../planner/building/dml-target.js').resolveCteTarget}):
498
+ * an UNQUALIFIED target name that matches a member of the statement's OWN
499
+ * leading WITH clause binds that CTE — which shadows a same-named schema
500
+ * object as a write target — so it is not a table reference; a
501
+ * schema-qualified target never binds a CTE. Enclosing statements' CTEs do
502
+ * NOT shadow a write target (the resolver consults only the statement's own
503
+ * clause), so only `withClause` is checked here, not the scope stack.
504
+ */
505
+ function visitDmlTarget(id, withClause, state) {
506
+ if (state.stop)
507
+ return;
508
+ if (id.schema === undefined && (withClause?.ctes ?? []).some(c => eq(c.name, id.name)))
509
+ return;
510
+ emit(state, {
511
+ schema: id.schema,
512
+ name: id.name,
513
+ setName: next => { id.name = next; },
514
+ // A DML target re-resolves through the catalog when the body is next
515
+ // planned, so it can carry the post-condition qualifier.
516
+ qualify: schemaName => { id.schema = schemaName; },
517
+ // The statement's OWN WITH can capture an unqualified target the rename
518
+ // gives a member's name (`resolveCteTarget` binds it as a write target);
519
+ // enclosing statements' CTEs cannot, so only `withClause` is consulted.
520
+ cteShadows: next => id.schema === undefined && (withClause?.ctes ?? []).some(c => eq(c.name, next)),
521
+ });
522
+ }
523
+ /**
524
+ * Visit the clauses an UPDATE / DELETE evaluates against its TARGET row — the
525
+ * assignments, WHERE, RETURNING and mutation-context values — inside a frame
526
+ * binding the statement's target correlation name.
527
+ *
528
+ * That name is a qualifier, never a table: it is the mandatory alias of an
529
+ * inline subquery target (`update (select …) as v set … where v.k = 1`) or the
530
+ * collision-proof one the view-mutation lowering synthesizes for a named
531
+ * target. Renaming a table that happens to share it must leave `v.k` alone,
532
+ * exactly as a FROM alias is left alone — and the alias itself never moves, so
533
+ * rewriting the qualifier would only break the reference.
534
+ */
535
+ function visitDmlTargetRowClauses(stmt, state) {
536
+ const frame = emptyTableFrame();
537
+ if (stmt.alias)
538
+ frame.bound.set(stmt.alias.toLowerCase(), null);
539
+ state.stack.push(frame);
540
+ try {
541
+ if (stmt.type === 'update')
542
+ stmt.assignments.forEach(a => visitTableRefs(a.value, state));
543
+ visitTableRefs(stmt.where, state);
544
+ (stmt.returning ?? []).forEach(r => {
545
+ if (r.type === 'column')
546
+ visitTableRefs(r.expr, state);
547
+ });
548
+ (stmt.contextValues ?? []).forEach(cv => visitTableRefs(cv.value, state));
549
+ }
550
+ finally {
551
+ state.stack.pop();
552
+ }
553
+ }
554
+ /**
555
+ * Visit a `with inverse` assignment expression or `with defaults` entry
556
+ * expression with the row-image suppression forced ON, restoring the ambient
557
+ * flag after — the table-walker twin of the column walker's
558
+ * `visitRowImageForeignSubtree`. Unconditional on purpose: these subtrees are
559
+ * written-row context of their enclosing select wherever the walk entered, so a
560
+ * reached view body self-suppresses even though the entry point (rightly)
561
+ * passed no `rowImageContext` for it.
562
+ */
563
+ function visitRowImageSubtree(expr, state) {
564
+ const ambient = state.rowImage;
565
+ state.rowImage = true;
566
+ try {
567
+ visitTableRefs(expr, state);
568
+ }
569
+ finally {
570
+ state.rowImage = ambient;
571
+ }
572
+ }
573
+ function visitTableRefs(node, state) {
574
+ if (!node || state.stop)
575
+ return;
576
+ switch (node.type) {
577
+ case 'select': {
578
+ const stmt = node;
579
+ pushWithFrame(stmt.withClause, state);
580
+ try {
581
+ const frame = emptyTableFrame();
582
+ (stmt.from ?? []).forEach(f => collectFromBindings(f, state, frame));
583
+ frame.subtreeRoot = stmt;
584
+ state.stack.push(frame);
585
+ try {
586
+ (stmt.columns ?? []).forEach(c => {
587
+ if (c.type === 'column') {
588
+ visitTableRefs(c.expr, state);
589
+ // A `with inverse` assignment expr can embed a subquery naming any
590
+ // table; the assignment's target names a base COLUMN, untouched by a
591
+ // table rename (same as the `with defaults` clause below). Both sit
592
+ // in this body's FROM frame — but the expr is written-row context
593
+ // of the ENCLOSING select regardless of the walk's entry point: a
594
+ // bare unbound `new.<x>` there names an output column of this
595
+ // select (docs/sql-select.md § Result-column inverses), never a
596
+ // table called `new`, so the row-image suppression is forced over
597
+ // the subtree (the column walker forces `'foreign'` over the same
598
+ // one).
599
+ (c.inverse ?? []).forEach(a => visitRowImageSubtree(a.expr, state));
600
+ }
601
+ });
602
+ // `with defaults` clause: each entry's `expr` (an inserted-row default) can
603
+ // embed a subquery naming any table; the entry's `column` names a base
604
+ // COLUMN, untouched by a table rename. A defaults entry is documented
605
+ // self-contained — it cannot reference the inserted row — but nothing
606
+ // enforces that at CREATE VIEW time, so a bare unbound `new.` / `old.`
607
+ // there is pinned inert the same way (column-walker parity; such a ref
608
+ // could never plan as a table reference anyway).
609
+ (stmt.defaults ?? []).forEach(d => visitRowImageSubtree(d.expr, state));
610
+ (stmt.from ?? []).forEach(f => visitTableRefs(f, state));
611
+ visitTableRefs(stmt.where, state);
612
+ (stmt.groupBy ?? []).forEach(g => visitTableRefs(g, state));
613
+ visitTableRefs(stmt.having, state);
614
+ (stmt.orderBy ?? []).forEach(o => visitTableRefs(o.expr, state));
615
+ visitTableRefs(stmt.limit, state);
616
+ visitTableRefs(stmt.offset, state);
617
+ // Set-op legs stay inside this select's frames (mirroring the column
618
+ // walker): each leg is its own select and pushes its own frames on top.
619
+ visitTableRefs(stmt.union, state);
620
+ if (stmt.compound)
621
+ visitTableRefs(stmt.compound.select, state);
622
+ }
623
+ finally {
624
+ state.stack.pop();
625
+ }
626
+ }
627
+ finally {
628
+ state.stack.pop();
629
+ }
630
+ break;
631
+ }
632
+ case 'insert': {
633
+ const stmt = node;
634
+ pushWithFrame(stmt.withClause, state);
635
+ try {
636
+ visitDmlTarget(stmt.table, stmt.withClause, state);
637
+ visitTableRefs(stmt.source, state);
638
+ (stmt.upsertClauses ?? []).forEach(uc => {
639
+ (uc.assignments ?? []).forEach(a => visitTableRefs(a.value, state));
640
+ visitTableRefs(uc.where, state);
641
+ });
642
+ (stmt.returning ?? []).forEach(r => {
643
+ if (r.type === 'column')
644
+ visitTableRefs(r.expr, state);
645
+ });
646
+ (stmt.contextValues ?? []).forEach(cv => visitTableRefs(cv.value, state));
647
+ }
648
+ finally {
649
+ state.stack.pop();
650
+ }
651
+ break;
652
+ }
653
+ case 'update':
654
+ case 'delete': {
655
+ const stmt = node;
656
+ pushWithFrame(stmt.withClause, state);
657
+ try {
658
+ // An inline subquery target (`update (select …) as v set …`): `table` is a
659
+ // synthetic placeholder equal to the alias, not a table reference — the real
660
+ // references live inside the subquery body. Visited OUTSIDE the target frame
661
+ // below: the body cannot see its own correlation name.
662
+ if (stmt.targetSource)
663
+ visitTableRefs(stmt.targetSource, state);
664
+ else
665
+ visitDmlTarget(stmt.table, stmt.withClause, state);
666
+ visitDmlTargetRowClauses(stmt, state);
667
+ }
668
+ finally {
669
+ state.stack.pop();
670
+ }
671
+ break;
672
+ }
673
+ case 'values': {
674
+ const stmt = node;
675
+ stmt.values.forEach(row => row.forEach(v => visitTableRefs(v, state)));
676
+ break;
677
+ }
678
+ case 'table': {
679
+ const ts = node;
680
+ // A FROM source. An unqualified name that a CTE in scope declares binds
681
+ // the CTE, not a same-named real table; a schema-qualified source
682
+ // (`main.zap`) is never a CTE. The alias, if any, does not matter here —
683
+ // `from zap z` still reads the real table.
684
+ if (!(ts.table.schema === undefined && isCteInScope(state, ts.table.name.toLowerCase()))) {
685
+ // The top of the stack IS this source's own FROM frame: `case 'table'`
686
+ // is reachable only from a select's `from` array (directly or through
687
+ // `join` — UPDATE/DELETE targets are typed `AST.SubquerySource`), and
688
+ // the select arm pushes the FROM frame before visiting it.
689
+ const sourceFrameIndex = state.stack.length - 1;
690
+ const ref = {
691
+ schema: ts.table.schema,
692
+ name: ts.table.name,
693
+ setName: next => { ts.table.name = next; },
694
+ // A FROM source re-resolves through the catalog, so it can carry
695
+ // the post-condition qualifier. Column qualifiers bound through
696
+ // this source are unaffected: their frame bindings were copied by
697
+ // value BEFORE anything under the FROM was visited, and a
698
+ // qualified `main.t2` source still exposes the bare qualifier
699
+ // `t2` to the rows it produces.
700
+ qualify: schemaName => { ts.table.schema = schemaName; },
701
+ // The catalog resolvers cannot see a CTE capturing the new name.
702
+ cteShadows: next => ts.table.schema === undefined && isCteInScope(state, next.toLowerCase()),
703
+ };
704
+ if (ts.alias === undefined) {
705
+ // Only an unaliased source exposes its own name as a qualifier;
706
+ // an aliased one exposes the alias, which a rename never moves.
707
+ ref.qualifierCollides = next => qualifierCollidesAt(state, next.toLowerCase(), sourceFrameIndex);
708
+ ref.aliasAs = aliasName => { ts.alias = aliasName; };
709
+ }
710
+ emit(state, ref);
711
+ }
712
+ break;
713
+ }
714
+ case 'join': {
715
+ const join = node;
716
+ visitTableRefs(join.left, state);
717
+ visitTableRefs(join.right, state);
718
+ visitTableRefs(join.condition, state);
719
+ break;
720
+ }
721
+ case 'functionSource': {
722
+ const fs = node;
723
+ fs.args.forEach(a => visitTableRefs(a, state));
724
+ break;
725
+ }
726
+ case 'subquerySource': {
727
+ const ss = node;
728
+ visitTableRefs(ss.subquery, state);
729
+ break;
730
+ }
731
+ case 'binary': {
732
+ const e = node;
733
+ visitTableRefs(e.left, state);
734
+ visitTableRefs(e.right, state);
735
+ break;
736
+ }
737
+ case 'unary':
738
+ case 'cast':
739
+ case 'collate': {
740
+ visitTableRefs(node.expr, state);
741
+ break;
742
+ }
743
+ case 'function': {
744
+ node.args.forEach(a => visitTableRefs(a, state));
745
+ break;
746
+ }
747
+ case 'subquery': {
748
+ visitTableRefs(node.query, state);
749
+ break;
750
+ }
751
+ case 'windowFunction': {
752
+ const wf = node;
753
+ visitTableRefs(wf.function, state);
754
+ visitTableRefs(wf.window, state);
755
+ break;
756
+ }
757
+ case 'windowDefinition': {
758
+ const wd = node;
759
+ (wd.partitionBy ?? []).forEach(p => visitTableRefs(p, state));
760
+ (wd.orderBy ?? []).forEach(o => visitTableRefs(o.expr, state));
761
+ break;
762
+ }
763
+ case 'case': {
764
+ const ce = node;
765
+ visitTableRefs(ce.baseExpr, state);
766
+ ce.whenThenClauses.forEach(wt => {
767
+ visitTableRefs(wt.when, state);
768
+ visitTableRefs(wt.then, state);
769
+ });
770
+ visitTableRefs(ce.elseExpr, state);
771
+ break;
772
+ }
773
+ case 'in': {
774
+ const ie = node;
775
+ visitTableRefs(ie.expr, state);
776
+ (ie.values ?? []).forEach(v => visitTableRefs(v, state));
777
+ visitTableRefs(ie.subquery, state);
778
+ break;
779
+ }
780
+ case 'exists': {
781
+ visitTableRefs(node.subquery, state);
782
+ break;
783
+ }
784
+ case 'between': {
785
+ const be = node;
786
+ visitTableRefs(be.expr, state);
787
+ visitTableRefs(be.lower, state);
788
+ visitTableRefs(be.upper, state);
789
+ break;
790
+ }
791
+ case 'column': {
792
+ const col = node;
793
+ if (!col.table)
794
+ break;
795
+ if (col.schema !== undefined) {
796
+ // A schema-qualified qualifier (`main.zap.k`) can never be a CTE, an
797
+ // alias, or a row image — always a real table reference. No `qualify`:
798
+ // it only matches when its written schema IS the renamed schema, so
799
+ // the rewrite post-condition holds by construction (a qualified name
800
+ // resolves by passthrough).
801
+ emit(state, {
802
+ schema: col.schema,
803
+ name: col.table,
804
+ setName: next => { col.table = next; },
805
+ });
806
+ break;
807
+ }
808
+ const qualifierLower = col.table.toLowerCase();
809
+ const resolved = resolveQualifier(state, qualifierLower);
810
+ if (resolved === undefined) {
811
+ // Nothing in scope binds the qualifier: a seedless expression context
812
+ // (a CHECK / index-predicate self-qualifier, or correlation the walk
813
+ // cannot see). Treat as a direct table reference — except the row
814
+ // image in a written-row context.
815
+ if (state.rowImage && (qualifierLower === 'new' || qualifierLower === 'old'))
816
+ break;
817
+ emit(state, {
818
+ schema: undefined,
819
+ name: col.table,
820
+ setName: next => { col.table = next; },
821
+ // Seedless, so it re-resolves through the catalog and can carry
822
+ // the post-condition qualifier. In practice this only ever fires
823
+ // on an already-unevaluable body: a CHECK / DEFAULT plans under
824
+ // its owning schema ONLY (`schemaAuthoredContext`), so a bare
825
+ // qualifier that resolves by falling through to ANOTHER schema —
826
+ // the only way the post-condition can fail here — is one the
827
+ // planner already rejects. Harmless, arguably an improvement.
828
+ qualify: schemaName => { col.schema = schemaName; },
829
+ });
830
+ }
831
+ else if (resolved.binding !== null) {
832
+ // Bound by an unaliased real table source: the qualifier IS that
833
+ // table's name. Report under the SOURCE's identity so a source in
834
+ // another schema doesn't match by bare name. No `qualify`: this
835
+ // reference binds through the FROM frame, not the catalog —
836
+ // qualifying the SOURCE (the `table` case above) is what preserves
837
+ // resolution; the qualifier just needs the new bare name.
838
+ const { binding, frameIndex } = resolved;
839
+ emit(state, {
840
+ schema: binding.schema,
841
+ name: binding.name,
842
+ setName: next => { col.table = next; },
843
+ // Evaluated at the BINDING frame — the source's own depth — so
844
+ // this answer always matches the source emit's (same frame,
845
+ // same memoized subtree set). No `aliasAs`: when this fires,
846
+ // the sink leaves the qualifier's old spelling in place and
847
+ // the SOURCE gains the alias that keeps it bound.
848
+ qualifierCollides: next => qualifierCollidesAt(state, next.toLowerCase(), frameIndex),
849
+ });
850
+ }
851
+ // resolved.binding === null: an alias / CTE / subquery / function source
852
+ // — the qualifier is not a table name; nothing to report.
853
+ break;
854
+ }
855
+ // Leaf nodes / DDL — nothing to recurse into for our purposes.
856
+ default:
857
+ break;
858
+ }
859
+ }
860
+ //# sourceMappingURL=table-rename.js.map