@quereus/quereus 4.8.0 → 4.9.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 (157) 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 +26 -1
  4. package/dist/src/core/database.js.map +1 -1
  5. package/dist/src/func/builtins/aggregate.d.ts.map +1 -1
  6. package/dist/src/func/builtins/aggregate.js +3 -2
  7. package/dist/src/func/builtins/aggregate.js.map +1 -1
  8. package/dist/src/func/builtins/conversion.d.ts +5 -0
  9. package/dist/src/func/builtins/conversion.d.ts.map +1 -1
  10. package/dist/src/func/builtins/conversion.js +16 -2
  11. package/dist/src/func/builtins/conversion.js.map +1 -1
  12. package/dist/src/func/builtins/index.d.ts.map +1 -1
  13. package/dist/src/func/builtins/index.js +5 -2
  14. package/dist/src/func/builtins/index.js.map +1 -1
  15. package/dist/src/func/builtins/string.d.ts +2 -0
  16. package/dist/src/func/builtins/string.d.ts.map +1 -1
  17. package/dist/src/func/builtins/string.js +60 -4
  18. package/dist/src/func/builtins/string.js.map +1 -1
  19. package/dist/src/index.d.ts +6 -3
  20. package/dist/src/index.d.ts.map +1 -1
  21. package/dist/src/index.js +15 -2
  22. package/dist/src/index.js.map +1 -1
  23. package/dist/src/planner/building/constraint-builder.js +1 -1
  24. package/dist/src/planner/building/constraint-builder.js.map +1 -1
  25. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.d.ts.map +1 -1
  26. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +121 -51
  27. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
  28. package/dist/src/planner/rules/shared/index-style-context.d.ts +14 -4
  29. package/dist/src/planner/rules/shared/index-style-context.d.ts.map +1 -1
  30. package/dist/src/planner/rules/shared/index-style-context.js +14 -4
  31. package/dist/src/planner/rules/shared/index-style-context.js.map +1 -1
  32. package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
  33. package/dist/src/runtime/emit/alter-table.js +212 -155
  34. package/dist/src/runtime/emit/alter-table.js.map +1 -1
  35. package/dist/src/runtime/emit/assertion-drop-guard.d.ts +26 -12
  36. package/dist/src/runtime/emit/assertion-drop-guard.d.ts.map +1 -1
  37. package/dist/src/runtime/emit/assertion-drop-guard.js +45 -26
  38. package/dist/src/runtime/emit/assertion-drop-guard.js.map +1 -1
  39. package/dist/src/runtime/emit/assertion-rename-helpers.d.ts +6 -6
  40. package/dist/src/runtime/emit/assertion-rename-helpers.d.ts.map +1 -1
  41. package/dist/src/runtime/emit/assertion-rename-helpers.js +18 -20
  42. package/dist/src/runtime/emit/assertion-rename-helpers.js.map +1 -1
  43. package/dist/src/runtime/emit/binary.d.ts.map +1 -1
  44. package/dist/src/runtime/emit/binary.js +12 -10
  45. package/dist/src/runtime/emit/binary.js.map +1 -1
  46. package/dist/src/runtime/emit/column-rename-cascade.d.ts +84 -0
  47. package/dist/src/runtime/emit/column-rename-cascade.d.ts.map +1 -0
  48. package/dist/src/runtime/emit/column-rename-cascade.js +134 -0
  49. package/dist/src/runtime/emit/column-rename-cascade.js.map +1 -0
  50. package/dist/src/runtime/emit/drop-column-guards.d.ts +82 -53
  51. package/dist/src/runtime/emit/drop-column-guards.d.ts.map +1 -1
  52. package/dist/src/runtime/emit/drop-column-guards.js +155 -90
  53. package/dist/src/runtime/emit/drop-column-guards.js.map +1 -1
  54. package/dist/src/runtime/emit/drop-table.d.ts.map +1 -1
  55. package/dist/src/runtime/emit/drop-table.js +5 -0
  56. package/dist/src/runtime/emit/drop-table.js.map +1 -1
  57. package/dist/src/runtime/emit/drop-view.d.ts.map +1 -1
  58. package/dist/src/runtime/emit/drop-view.js +5 -0
  59. package/dist/src/runtime/emit/drop-view.js.map +1 -1
  60. package/dist/src/runtime/emit/expression-drop-guard.d.ts +57 -0
  61. package/dist/src/runtime/emit/expression-drop-guard.d.ts.map +1 -0
  62. package/dist/src/runtime/emit/expression-drop-guard.js +82 -0
  63. package/dist/src/runtime/emit/expression-drop-guard.js.map +1 -0
  64. package/dist/src/runtime/emit/materialized-view-helpers.d.ts +26 -9
  65. package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -1
  66. package/dist/src/runtime/emit/materialized-view-helpers.js +37 -17
  67. package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -1
  68. package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -1
  69. package/dist/src/runtime/emit/materialized-view.js +3 -0
  70. package/dist/src/runtime/emit/materialized-view.js.map +1 -1
  71. package/dist/src/schema/assertion.d.ts +58 -0
  72. package/dist/src/schema/assertion.d.ts.map +1 -1
  73. package/dist/src/schema/assertion.js +78 -0
  74. package/dist/src/schema/assertion.js.map +1 -1
  75. package/dist/src/schema/catalog-persistability.d.ts +11 -3
  76. package/dist/src/schema/catalog-persistability.d.ts.map +1 -1
  77. package/dist/src/schema/catalog-persistability.js +48 -29
  78. package/dist/src/schema/catalog-persistability.js.map +1 -1
  79. package/dist/src/schema/catalog.d.ts +22 -0
  80. package/dist/src/schema/catalog.d.ts.map +1 -1
  81. package/dist/src/schema/catalog.js +4 -1
  82. package/dist/src/schema/catalog.js.map +1 -1
  83. package/dist/src/schema/column-republication.d.ts +126 -0
  84. package/dist/src/schema/column-republication.d.ts.map +1 -0
  85. package/dist/src/schema/column-republication.js +121 -0
  86. package/dist/src/schema/column-republication.js.map +1 -0
  87. package/dist/src/schema/column-source-resolver.d.ts +29 -6
  88. package/dist/src/schema/column-source-resolver.d.ts.map +1 -1
  89. package/dist/src/schema/column-source-resolver.js +78 -9
  90. package/dist/src/schema/column-source-resolver.js.map +1 -1
  91. package/dist/src/schema/expression-dependents.d.ts +160 -0
  92. package/dist/src/schema/expression-dependents.d.ts.map +1 -0
  93. package/dist/src/schema/expression-dependents.js +228 -0
  94. package/dist/src/schema/expression-dependents.js.map +1 -0
  95. package/dist/src/schema/object-dependency-closure.d.ts +127 -0
  96. package/dist/src/schema/object-dependency-closure.d.ts.map +1 -0
  97. package/dist/src/schema/object-dependency-closure.js +117 -0
  98. package/dist/src/schema/object-dependency-closure.js.map +1 -0
  99. package/dist/src/schema/object-ref-resolver.d.ts +83 -0
  100. package/dist/src/schema/object-ref-resolver.d.ts.map +1 -0
  101. package/dist/src/schema/object-ref-resolver.js +135 -0
  102. package/dist/src/schema/object-ref-resolver.js.map +1 -0
  103. package/dist/src/schema/rename/column-rename.d.ts +228 -0
  104. package/dist/src/schema/rename/column-rename.d.ts.map +1 -0
  105. package/dist/src/schema/rename/column-rename.js +1225 -0
  106. package/dist/src/schema/rename/column-rename.js.map +1 -0
  107. package/dist/src/schema/rename/self-qualifier-strip.d.ts +29 -0
  108. package/dist/src/schema/rename/self-qualifier-strip.d.ts.map +1 -0
  109. package/dist/src/schema/rename/self-qualifier-strip.js +267 -0
  110. package/dist/src/schema/rename/self-qualifier-strip.js.map +1 -0
  111. package/dist/src/schema/rename/shared.d.ts +108 -0
  112. package/dist/src/schema/rename/shared.d.ts.map +1 -0
  113. package/dist/src/schema/rename/shared.js +49 -0
  114. package/dist/src/schema/rename/shared.js.map +1 -0
  115. package/dist/src/schema/rename/table-rename.d.ts +263 -0
  116. package/dist/src/schema/rename/table-rename.d.ts.map +1 -0
  117. package/dist/src/schema/rename/table-rename.js +860 -0
  118. package/dist/src/schema/rename/table-rename.js.map +1 -0
  119. package/dist/src/schema/rename-rewriter.d.ts +18 -278
  120. package/dist/src/schema/rename-rewriter.d.ts.map +1 -1
  121. package/dist/src/schema/rename-rewriter.js +17 -1506
  122. package/dist/src/schema/rename-rewriter.js.map +1 -1
  123. package/dist/src/schema/schema-differ.d.ts.map +1 -1
  124. package/dist/src/schema/schema-differ.js +228 -21
  125. package/dist/src/schema/schema-differ.js.map +1 -1
  126. package/dist/src/types/builtin-types.d.ts.map +1 -1
  127. package/dist/src/types/builtin-types.js +12 -28
  128. package/dist/src/types/builtin-types.js.map +1 -1
  129. package/dist/src/types/cast-semantics.d.ts +7 -5
  130. package/dist/src/types/cast-semantics.d.ts.map +1 -1
  131. package/dist/src/types/cast-semantics.js +20 -9
  132. package/dist/src/types/cast-semantics.js.map +1 -1
  133. package/dist/src/types/index.d.ts +1 -1
  134. package/dist/src/types/index.d.ts.map +1 -1
  135. package/dist/src/types/index.js +1 -1
  136. package/dist/src/types/index.js.map +1 -1
  137. package/dist/src/types/registry.d.ts.map +1 -1
  138. package/dist/src/types/registry.js +2 -1
  139. package/dist/src/types/registry.js.map +1 -1
  140. package/dist/src/types/temporal-types.d.ts +11 -0
  141. package/dist/src/types/temporal-types.d.ts.map +1 -1
  142. package/dist/src/types/temporal-types.js +82 -0
  143. package/dist/src/types/temporal-types.js.map +1 -1
  144. package/dist/src/util/affinity.d.ts +2 -1
  145. package/dist/src/util/affinity.d.ts.map +1 -1
  146. package/dist/src/util/affinity.js +16 -5
  147. package/dist/src/util/affinity.js.map +1 -1
  148. package/dist/src/util/ast-spine-clone.d.ts +2 -2
  149. package/dist/src/util/ast-spine-clone.js +2 -2
  150. package/dist/src/util/value-text.d.ts +48 -0
  151. package/dist/src/util/value-text.d.ts.map +1 -0
  152. package/dist/src/util/value-text.js +35 -0
  153. package/dist/src/util/value-text.js.map +1 -0
  154. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  155. package/dist/src/vtab/memory/layer/manager.js +14 -5
  156. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  157. package/package.json +3 -3
@@ -7,17 +7,19 @@ import { createLogger } from '../../common/logger.js';
7
7
  import { buildColumnIndexMap, withGeneratedColumnGraph, requireVtabModule, resolveNamedConstraintClass, namedConstraintExists, assertConstraintNameFree, validateCollationForType, columnDefToSchema } from '../../schema/table.js';
8
8
  import { validateForeignKeyCollations, buildForeignKeyConstraintSchema, extractColumnLevelCheckConstraints, extractColumnLevelForeignKeys, extractColumnLevelUniqueConstraints } from '../../schema/constraint-builder.js';
9
9
  import { quoteIdentifier, expressionToString, astToString } from '../../emit/ast-stringify.js';
10
- import { renameTableInAst, renameColumnInAst, renameColumnInCheckExpression, renameColumnInColumnExpressions, renameTableInColumnExpressions } from '../../schema/rename-rewriter.js';
10
+ import { renameTableInAst, renameColumnInAst, renameColumnInCheckExpression, renameColumnInColumnExpressions, renameTableInCheckConstraints, renameTableInIndexPredicates, renameTableInColumnExpressions, objectRefKey } from '../../schema/rename-rewriter.js';
11
+ import { snapshotObjectRefResolvers, tableRenameTargetsFor } from '../../schema/object-ref-resolver.js';
11
12
  import { assertCatalogObjectPersistable, assertRenameDependentsPersistable } from '../../schema/catalog-persistability.js';
12
13
  import { assertUniqueConstraintIndexNameFree, assertUniqueConstraintNotDuplicated, uniqueConstraintColumnSetKey } from '../../schema/catalog.js';
13
14
  import { isTruthy } from '../../util/comparison.js';
14
15
  import { assertDdlTransactionPolicy, isExplicitTransactionOpen } from './ddl-transaction-policy.js';
15
16
  import { buildColumnSourceResolver } from '../../schema/column-source-resolver.js';
16
- import { assertNoColumnDefaultNamesColumn, assertNoCheckConstraintNamesColumn, assertNoAssertionNamesColumn, assertNoForeignKeyReferencesColumn } from './drop-column-guards.js';
17
+ import { assertNoColumnExpressionNamesColumn, assertNoCheckConstraintNamesColumn, assertNoAssertionNamesColumn, assertNoForeignKeyReferencesColumn } from './drop-column-guards.js';
17
18
  import { emitAlterSchemaEvent, withStatementScopedSchemaEvents } from './alter-schema-event.js';
18
19
  import { foldDefaultToType, validateAndParse } from '../../types/validation.js';
19
20
  import { snapshotStaleMaterializedViews, propagateTableRenameToMaterializedViews, propagateColumnRenameToMaterializedViews, restoreUnaffectedMaterializedViews, attachMaintainedDerivation, detachMaintainedDerivation, } from './materialized-view-helpers.js';
20
21
  import { propagateTableRenameToAssertions, propagateColumnRenameToAssertions, } from './assertion-rename-helpers.js';
22
+ import { assertColumnRenameCascadePublishable, runColumnRenameCascade } from './column-rename-cascade.js';
21
23
  import { isMaintainedTable } from '../../schema/derivation.js';
22
24
  import { inferType } from '../../types/registry.js';
23
25
  const log = createLogger('runtime:emit:alter-table');
@@ -174,6 +176,17 @@ async function runRenameTable(rctx, tableSchema, schema, newName, sql) {
174
176
  if (schema.getTable(newName)) {
175
177
  throw new QuereusError(`Table '${newName}' already exists`, StatusCode.ERROR);
176
178
  }
179
+ // Reference resolution for every walk this statement runs, snapshotted BEFORE
180
+ // the first side effect: the propagation below rewrites dependents after the
181
+ // catalog swap, and each reference must resolve the way its body PLANNED —
182
+ // against the pre-rename catalog — or a bare `t` would fall through to a
183
+ // same-named table further down the schema path once `main.t` is gone.
184
+ // `targetFor` pairs that pre-mutation resolution with its post-rename sibling
185
+ // snapshot, per body-owning home schema, so every rewrite can hold its
186
+ // post-condition (a rewritten reference still resolves to the renamed table,
187
+ // schema-qualifying when the bare new name would otherwise re-bind).
188
+ const objectResolvers = snapshotObjectRefResolvers(rctx.db);
189
+ const targetFor = tableRenameTargetsFor(objectResolvers, tableSchema.schemaName, oldName, newName);
177
190
  // Pre-flight, BEFORE the first side effect (`module.renameTable`): every catalog
178
191
  // entry this rename would rewrite must still be persistable. Both the rename
179
192
  // propagation and the store's catalog write are unfailable (notifier try/catch,
@@ -187,7 +200,7 @@ async function runRenameTable(rctx, tableSchema, schema, newName, sql) {
187
200
  // substitutes `newName`, which is already under test as the record's own name.
188
201
  assertCatalogObjectPersistable(rctx.db, 'materializedView', { ...tableSchema, name: newName });
189
202
  }
190
- assertRenameDependentsPersistable(rctx.db, schema, ast => renameTableInAst(ast, oldName, newName, tableSchema.schemaName), t => rewriteTableForTableRename(t, tableSchema.schemaName.toLowerCase(), oldName, newName));
203
+ assertRenameDependentsPersistable(rctx.db, home => ast => renameTableInAst(ast, targetFor(home)), t => rewriteTableForTableRename(t, targetFor));
191
204
  // Clone schema with new name
192
205
  const updatedTableSchema = {
193
206
  ...tableSchema,
@@ -230,7 +243,7 @@ async function runRenameTable(rctx, tableSchema, schema, newName, sql) {
230
243
  // vanished old name. `propagateTableRename` runs the same rewrite over every
231
244
  // table in the catalog, but only after the notify; it is idempotent, so this
232
245
  // call simply makes that pass a no-op for this one table.
233
- const renamedTableSchema = rewriteTableForTableRename(updatedTableSchema, tableSchema.schemaName.toLowerCase(), oldName, newName);
246
+ const renamedTableSchema = rewriteTableForTableRename(updatedTableSchema, targetFor);
234
247
  // Remove old, add new in the catalog
235
248
  schema.removeTable(oldName);
236
249
  schema.addTable(renamedTableSchema);
@@ -251,7 +264,7 @@ async function runRenameTable(rctx, tableSchema, schema, newName, sql) {
251
264
  // predicates in this and other tables, view and materialized-view bodies).
252
265
  // Best-effort AST rewrite — there is no global dependency tracker yet, so we
253
266
  // walk the catalog and patch in-place.
254
- await propagateTableRename(rctx, tableSchema.schemaName, oldName, newName, preStaleMvs);
267
+ await propagateTableRename(rctx, preStaleMvs, targetFor);
255
268
  // Renaming a MAINTAINED table is an ordinary table rename plus a maintenance
256
269
  // re-key: the row-time plan is keyed by `schema.name`, so release the old key
257
270
  // and re-register under the new one, then move the persisted MV catalog entry
@@ -310,10 +323,24 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName, sql)
310
323
  // resolver with `propagateColumnRename` so the two passes cannot drift apart in
311
324
  // code; what makes them agree at RUNTIME (the resolver reads the LIVE catalog, and
312
325
  // this probe runs pre-mutation while the propagation runs post-) is that
313
- // `isTableInUnaliasedScope` skips the renamed table itself and probes only OTHER
326
+ // `unqualifiedRefBindsTarget` skips the renamed table itself and probes only OTHER
314
327
  // sources, whose column sets this rename does not touch.
315
- const resolveColumnInSource = buildColumnSourceResolver(rctx.db.schemaManager);
316
- assertRenameDependentsPersistable(rctx.db, schema, ast => renameColumnInAst(ast, tableSchema.name, oldName, newName, tableSchema.schemaName, resolveColumnInSource), t => rewriteTableForColumnRename(t, tableSchema.schemaName.toLowerCase(), tableSchema.name, oldName, newName, resolveColumnInSource));
328
+ const resolveColumnInSource = buildColumnSourceResolver(rctx.db);
329
+ // Reference-resolution snapshot, BEFORE the first side effect — same discipline
330
+ // (and same reasoning) as the table-rename arm above.
331
+ const objectResolvers = snapshotObjectRefResolvers(rctx.db);
332
+ const renamedTableKey = objectRefKey(tableSchema.schemaName, tableSchema.name);
333
+ assertRenameDependentsPersistable(rctx.db,
334
+ // Row-image mode 'none': the probed bodies are view / MV bodies — relations
335
+ // with no written row (their `with inverse` / `with defaults` subtrees
336
+ // self-suppress inside the walker).
337
+ home => ast => renameColumnInAst(ast, tableSchema.name, oldName, newName, objectResolvers.forHomeSchema(home), renamedTableKey, 'none', resolveColumnInSource), t => rewriteTableForColumnRename(t, tableSchema.name, oldName, newName, objectResolvers, renamedTableKey, resolveColumnInSource));
338
+ // Pre-flight the CASCADE, still before the first side effect: a dependent view /
339
+ // materialized view whose published names the rename would shift must not end up
340
+ // publishing two columns of the new name (its own `newName` plus the shifted
341
+ // passthrough). The live cascade rewrites bodies in place with no rollback, so
342
+ // the refusal has to land here, while the statement is still a clean no-op.
343
+ assertColumnRenameCascadePublishable(rctx.db, { targetKey: renamedTableKey, tableName: tableSchema.name }, oldName, newName, objectResolvers, resolveColumnInSource);
317
344
  assertRenamedColumnBackingNamesFree(tableSchema, colIndex, oldName, newName);
318
345
  const existingCol = tableSchema.columns[colIndex];
319
346
  // Build a ColumnDef AST for the renamed column (preserving type info)
@@ -365,7 +392,7 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName, sql)
365
392
  });
366
393
  // Propagate the rename into dependent objects (CHECK / FK / partial-index
367
394
  // predicates in this and other tables, view and materialized-view bodies).
368
- await propagateColumnRename(rctx, tableSchema.schemaName, tableSchema.name, oldName, newName, preStaleMvs, resolveColumnInSource);
395
+ await propagateColumnRename(rctx, tableSchema.name, oldName, newName, preStaleMvs, objectResolvers, renamedTableKey, resolveColumnInSource);
369
396
  emitAlterSchemaEvent(rctx, tableSchema, {
370
397
  type: 'alter', objectType: 'column',
371
398
  objectName: tableSchema.name,
@@ -967,13 +994,15 @@ async function runDropColumn(rctx, tableSchema, schema, columnName, sql) {
967
994
  throw new QuereusError(`Cannot drop column '${columnName}' from '${tableSchema.name}': it is referenced by the WHERE clause of partial index '${idx.name}'`, StatusCode.CONSTRAINT);
968
995
  }
969
996
  }
970
- // Validate: the remaining dependents `module.alterTable` cannot narrow — a sibling
971
- // column's DEFAULT, a CHECK on this table, a foreign key in another table pointing AT
972
- // the column, and an assertion body. All four run before `requireVtabModule` /
997
+ // Validate: the remaining dependents `module.alterTable` cannot narrow — a column
998
+ // DEFAULT / generated body, a CHECK constraint, a foreign key in another table pointing
999
+ // AT the column, and an assertion body. All four run before `requireVtabModule` /
973
1000
  // `module.alterTable`, so a refused drop persists nothing. Ordered by widening blast
974
- // radius (a column of this table → this table → another table → the whole database), so
975
- // the most locally-explainable violation is the one reported.
976
- assertNoColumnDefaultNamesColumn(rctx.db, tableSchema, columnName);
1001
+ // radius (a column expression → a CHECK → a foreign key → the whole database), so the
1002
+ // most locally-explainable violation is the one reported. The first two scan every
1003
+ // table in every schema and report a dependent on the ALTERED table first, so their
1004
+ // messages for a same-table dependent are unchanged by that widening.
1005
+ assertNoColumnExpressionNamesColumn(rctx.db, tableSchema, columnName);
977
1006
  assertNoCheckConstraintNamesColumn(rctx.db, tableSchema, columnName);
978
1007
  assertNoForeignKeyReferencesColumn(rctx.db, tableSchema, columnName);
979
1008
  assertNoAssertionNamesColumn(rctx.db, tableSchema, columnName);
@@ -1666,30 +1695,40 @@ async function rebuildViaShadowTable(rctx, tableSchema, _schema, survivingColumn
1666
1695
  });
1667
1696
  }
1668
1697
  /**
1669
- * Propagates a table rename into every dependent schema object the catalog
1670
- * knows about: CHECK expressions, FK references, partial-index predicates,
1671
- * view bodies, and materialized-view bodies. Walks every schema (not just the
1672
- * renamed table's home schema) so cross-schema FK references are picked up.
1673
- * View `selectAst` is mutated in place because the planner re-walks it on
1674
- * every reference.
1698
+ * Propagates a table rename into every dependent schema object the catalog knows
1699
+ * about: CHECK expressions, FK references, partial-index predicates, view bodies,
1700
+ * assertion bodies, and materialized-view bodies. EVERY schema is walked for every
1701
+ * object kind — a view / assertion / MV elsewhere over the renamed table is as much a
1702
+ * dependent as a cross-schema foreign key, and the per-home-schema resolver is what
1703
+ * keeps that from over-matching (see {@link snapshotObjectRefResolvers}). View
1704
+ * `selectAst` is mutated in place because the planner re-walks it on every reference.
1705
+ *
1706
+ * Two global passes, not one combined per-schema pass: the MV pass re-plans each body
1707
+ * it rewrites, so every plain VIEW in every schema must already carry the new name
1708
+ * before the first MV re-plans — an MV in `main` may read a view in `temp`.
1675
1709
  */
1676
- async function propagateTableRename(rctx, renamedSchemaName, oldName, newName, preStaleMvs) {
1677
- for (const schema of rctx.db.schemaManager._getAllSchemas()) {
1678
- await propagateTableRenameInSchema(rctx.db, schema, renamedSchemaName, oldName, newName, preStaleMvs);
1710
+ async function propagateTableRename(rctx, preStaleMvs, targetFor) {
1711
+ const schemas = Array.from(rctx.db.schemaManager._getAllSchemas());
1712
+ for (const schema of schemas) {
1713
+ propagateTableRenameInSchema(rctx.db, schema, targetFor);
1714
+ }
1715
+ for (const schema of schemas) {
1716
+ await propagateTableRenameToMaterializedViews(rctx.db, schema, preStaleMvs, targetFor(schema.name));
1679
1717
  }
1680
1718
  // After all per-schema rewrites and their cascade events: restore any MV this
1681
1719
  // statement's events marked stale that the rename provably did not affect
1682
1720
  // (e.g. a dependent of another source whose only change was an FK rewrite).
1683
1721
  await restoreUnaffectedMaterializedViews(rctx.db, preStaleMvs);
1684
1722
  }
1685
- async function propagateTableRenameInSchema(db, schema, renamedSchemaName, oldName, newName, preStaleMvs) {
1723
+ /** Tables, views and assertions of one schema. Materialized views are a separate
1724
+ * global pass — see {@link propagateTableRename}. */
1725
+ function propagateTableRenameInSchema(db, schema, targetFor) {
1686
1726
  const notifier = db.schemaManager.getChangeNotifier();
1687
- const renamedSchemaLower = renamedSchemaName.toLowerCase();
1688
1727
  for (const table of Array.from(schema.getAllTables())) {
1689
- // Skip the just-renamed table when iterating the home schema; the FK
1690
- // `referencedTable` field on its own FKs (if any self-reference) is
1691
- // still pointing at the old name and needs rewriting too.
1692
- const updated = rewriteTableForTableRename(table, renamedSchemaLower, oldName, newName);
1728
+ // The just-renamed table is deliberately NOT skipped: it already carries its
1729
+ // new name, but a self-referencing FK's `referencedTable` (and its own CHECK /
1730
+ // DEFAULT / index-predicate ASTs) still name the old one and need rewriting.
1731
+ const updated = rewriteTableForTableRename(table, targetFor);
1693
1732
  if (updated !== table) {
1694
1733
  schema.addTable(updated);
1695
1734
  notifier.notifyChange({
@@ -1701,110 +1740,122 @@ async function propagateTableRenameInSchema(db, schema, renamedSchemaName, oldNa
1701
1740
  });
1702
1741
  }
1703
1742
  }
1704
- if (schema.name.toLowerCase() === renamedSchemaLower) {
1705
- for (const view of Array.from(schema.getAllViews())) {
1706
- // The body walk also descends the trailing `with defaults (…)` clause
1707
- // (now stored on `selectAst.defaults`), so a clause-only rewrite — a
1708
- // defaults-expr subquery referencing the renamed table even when the body
1709
- // never names it — flips `bodyChanged` and fires the (single) view_modified.
1710
- const bodyChanged = renameTableInAst(view.selectAst, oldName, newName, renamedSchemaName);
1711
- if (bodyChanged) {
1712
- const updatedView = { ...view, sql: astToString(view.selectAst) };
1713
- schema.addView(updatedView);
1714
- // The rewriter mutated `view.selectAst` (including its defaults clause) in
1715
- // place, so `oldObject` shares the rewritten AST (only `newObject.sql`
1716
- // differs). No consumer reads `oldObject.selectAst`; mirrors the table
1717
- // loop above (no clone).
1718
- notifier.notifyChange({
1719
- type: 'view_modified',
1720
- schemaName: schema.name,
1721
- objectName: updatedView.name,
1722
- oldObject: view,
1723
- newObject: updatedView,
1724
- });
1725
- }
1743
+ // Bodies owned by this schema resolve their unqualified names under ITS home
1744
+ // path — one target per schema walked, all over the pre-mutation snapshot. A
1745
+ // bare `t` matches only when it RESOLVES to the renamed object's key under that
1746
+ // path, so a `temp`-owned body meaning `temp.t` survives a rename of `main.t`.
1747
+ const target = targetFor(schema.name);
1748
+ for (const view of Array.from(schema.getAllViews())) {
1749
+ // The body walk also descends the trailing `with defaults (…)` clause
1750
+ // (now stored on `selectAst.defaults`), so a clause-only rewrite — a
1751
+ // defaults-expr subquery referencing the renamed table even when the body
1752
+ // never names it — flips `bodyChanged` and fires the (single) view_modified.
1753
+ const bodyChanged = renameTableInAst(view.selectAst, target);
1754
+ if (bodyChanged) {
1755
+ const updatedView = { ...view, sql: astToString(view.selectAst) };
1756
+ schema.addView(updatedView);
1757
+ // The rewriter mutated `view.selectAst` (including its defaults clause) in
1758
+ // place, so `oldObject` shares the rewritten AST (only `newObject.sql`
1759
+ // differs). No consumer reads `oldObject.selectAst`; mirrors the table
1760
+ // loop above (no clone).
1761
+ notifier.notifyChange({
1762
+ type: 'view_modified',
1763
+ schemaName: schema.name,
1764
+ objectName: updatedView.name,
1765
+ oldObject: view,
1766
+ newObject: updatedView,
1767
+ });
1726
1768
  }
1727
- // Assertions: same in-place body rewrite as plain views, plus a regenerated
1728
- // `violationSql` (the text the commit-time evaluator re-parses). Assertions
1729
- // feed no materialized view, so order against the MV pass is free; sitting
1730
- // next to the view loop keeps the plain schema-level objects together.
1731
- propagateTableRenameToAssertions(db, schema, renamedSchemaName, oldName, newName);
1732
- // Materialized views: same in-place body rewrite as plain views ("MV ≡
1733
- // faster view"), plus the derived-field re-key, row-time re-registration,
1734
- // and staleness discipline the MV record needs. Runs AFTER the view loop
1735
- // so a body reading the renamed table through a view re-plans against the
1736
- // already-rewritten view.
1737
- await propagateTableRenameToMaterializedViews(db, schema, renamedSchemaName, oldName, newName, preStaleMvs);
1738
1769
  }
1770
+ // Assertions: same in-place body rewrite as plain views, plus a regenerated
1771
+ // `violationSql` (the text the commit-time evaluator re-parses). Assertions
1772
+ // feed no materialized view, so order against the MV pass is free; sitting
1773
+ // next to the view loop keeps the plain schema-level objects together.
1774
+ propagateTableRenameToAssertions(db, schema, target);
1739
1775
  }
1740
- function rewriteTableForTableRename(table, renamedSchemaLower, oldName, newName) {
1741
- const oldLower = oldName.toLowerCase();
1776
+ /**
1777
+ * Rewrite one table's own definition for a table rename. The three
1778
+ * expression-bearing arms — CHECK constraints, partial-index predicates, and
1779
+ * column DEFAULT / generated bodies — go through the SAME collection helpers
1780
+ * the store module's catalog rewrite calls (`renameTableIn{CheckConstraints,
1781
+ * IndexPredicates,ColumnExpressions}`), so the per-arm row-image-context
1782
+ * decision (CHECKs and column expressions evaluate against a written row,
1783
+ * predicates do not) exists in exactly one place and the engine path and the
1784
+ * store path cannot disagree about it. The helpers rewrite in place and
1785
+ * report "did anything change", which is all the former hand-rolled loops
1786
+ * computed beyond the rewrite — their per-item `{...cc}` / `{...idx}` shallow
1787
+ * copies achieved nothing (the ASTs are shared by reference either way;
1788
+ * flipping `changed` is what re-registers the table and fires
1789
+ * `table_modified`).
1790
+ *
1791
+ * The FK arm stays hand-rolled: it maps a name field rather than walking an
1792
+ * AST, and an unqualified `referencedTable` binds the CHILD table's own
1793
+ * schema (never the session path — see `assertNoForeignKeyReferencesColumn`),
1794
+ * so the key comparison composes it from `fk.referencedSchema ?? table.schemaName`.
1795
+ */
1796
+ function rewriteTableForTableRename(table, targetFor) {
1797
+ const target = targetFor(table.schemaName);
1798
+ const targetKey = objectRefKey(target.schemaName, target.oldName);
1742
1799
  let changed = false;
1743
- const newChecks = table.checkConstraints.map(cc => {
1744
- const rewrote = renameTableInAst(cc.expr, oldName, newName, renamedSchemaLower);
1745
- if (!rewrote)
1746
- return cc;
1800
+ if (renameTableInCheckConstraints(table.checkConstraints, target))
1747
1801
  changed = true;
1748
- return { ...cc };
1749
- });
1750
1802
  const newFks = (table.foreignKeys ?? []).map(fk => {
1751
- const fkSchemaLower = (fk.referencedSchema ?? table.schemaName).toLowerCase();
1752
- if (fkSchemaLower !== renamedSchemaLower)
1753
- return fk;
1754
- if (fk.referencedTable.toLowerCase() !== oldLower)
1803
+ if (objectRefKey(fk.referencedSchema ?? table.schemaName, fk.referencedTable) !== targetKey)
1755
1804
  return fk;
1756
1805
  changed = true;
1757
- return { ...fk, referencedTable: newName };
1806
+ return { ...fk, referencedTable: target.newName };
1758
1807
  });
1759
1808
  // Partial-index predicates: the AST is mutated in place, so the derived
1760
1809
  // UNIQUE constraint of a unique partial index (which shares the predicate
1761
1810
  // by reference — see appendIndexToTableSchema) is rewritten with it.
1762
- const newIndexes = (table.indexes ?? []).map(idx => {
1763
- const rewrote = renameTableInAst(idx.predicate, oldName, newName, renamedSchemaLower);
1764
- if (!rewrote)
1765
- return idx;
1811
+ if (renameTableInIndexPredicates(table.indexes, target))
1766
1812
  changed = true;
1767
- return { ...idx };
1768
- });
1769
1813
  // Column-level expressions — a DEFAULT (`w integer default ((select min(v) from u))`)
1770
1814
  // and a generated column's body. Unlike the column verb's arm, no seeded/unseeded
1771
1815
  // split: `renameTableInAst` resolves nothing against an implicit owning table, so one
1772
1816
  // entry point covers the renamed table's own self-referencing default and every other
1773
1817
  // table's alike.
1774
- //
1775
- // Also unlike the collections above, no per-item shallow copy: the rewrite is in place
1776
- // and a `ColumnSchema`'s own fields are untouched, so a fresh column object would only
1777
- // make the catalog's array stop being identical to the one the module's rename hook
1778
- // just handed back. Flipping `changed` is what re-registers the table and fires
1779
- // `table_modified`, which is all the copies above achieve either.
1780
- const columnsRewritten = renameTableInColumnExpressions(table.columns, oldName, newName, renamedSchemaLower);
1781
- if (columnsRewritten)
1818
+ if (renameTableInColumnExpressions(table.columns, target))
1782
1819
  changed = true;
1783
1820
  if (!changed)
1784
1821
  return table;
1785
1822
  return Object.freeze({
1786
1823
  ...table,
1787
- checkConstraints: Object.freeze(newChecks),
1788
1824
  foreignKeys: table.foreignKeys ? Object.freeze(newFks) : table.foreignKeys,
1789
- indexes: table.indexes ? Object.freeze(newIndexes) : table.indexes,
1790
1825
  });
1791
1826
  }
1792
- async function propagateColumnRename(rctx, renamedSchemaName, tableName, oldCol, newCol, preStaleMvs, resolveColumnInSource) {
1793
- const schemaManager = rctx.db.schemaManager;
1794
- for (const schema of schemaManager._getAllSchemas()) {
1795
- await propagateColumnRenameInSchema(rctx.db, schema, renamedSchemaName, tableName, oldCol, newCol, resolveColumnInSource, preStaleMvs);
1796
- }
1797
- // After all per-schema rewrites and their cascade events: restore any MV this
1798
- // statement's events marked stale that the rename provably did not affect — a
1799
- // body that never names the renamed column, or a `select *` body whose output
1827
+ /**
1828
+ * The column-verb mirror of {@link propagateTableRename} — same all-schema scope for
1829
+ * every dependent object kind, same two-global-passes shape per round (views everywhere
1830
+ * before the first MV re-plans) — plus the one dimension the table verb does not have:
1831
+ * a rewritten view / MV body can SHIFT THE NAME the object publishes (a bare or `*`
1832
+ * passthrough of the renamed column), and the objects reading it then need the same
1833
+ * rename with the view as the target. The worklist lives in `column-rename-cascade.ts`;
1834
+ * each round re-enters the two passes below through the callback (threaded to avoid an
1835
+ * import cycle), so every dependent kind is covered at every depth.
1836
+ */
1837
+ async function propagateColumnRename(rctx, tableName, oldCol, newCol, preStaleMvs, resolvers, targetKey, resolveColumnInSource) {
1838
+ await runColumnRenameCascade(rctx.db, { targetKey, tableName }, oldCol, newCol, preStaleMvs, resolvers, resolveColumnInSource, async (target) => {
1839
+ const schemas = Array.from(rctx.db.schemaManager._getAllSchemas());
1840
+ for (const schema of schemas) {
1841
+ propagateColumnRenameInSchema(rctx.db, schema, target.tableName, oldCol, newCol, resolvers, target.targetKey, resolveColumnInSource);
1842
+ }
1843
+ for (const schema of schemas) {
1844
+ await propagateColumnRenameToMaterializedViews(rctx.db, schema, target.tableName, oldCol, newCol, preStaleMvs, resolvers.forHomeSchema(schema.name), target.targetKey, resolveColumnInSource);
1845
+ }
1846
+ });
1847
+ // After the whole cascade (once, not per round) and its events: restore any MV
1848
+ // this statement's events marked stale that the rename provably did not affect —
1849
+ // a body that never names the renamed column, or a `select *` body whose output
1800
1850
  // is a pure name shift (carried onto the live backing by the pass).
1801
1851
  await restoreUnaffectedMaterializedViews(rctx.db, preStaleMvs);
1802
1852
  }
1803
- async function propagateColumnRenameInSchema(db, schema, renamedSchemaName, tableName, oldCol, newCol, resolveColumnInSource, preStaleMvs) {
1853
+ /** Tables, views and assertions of one schema. Materialized views are a separate
1854
+ * global pass — see {@link propagateColumnRename}. */
1855
+ function propagateColumnRenameInSchema(db, schema, tableName, oldCol, newCol, resolvers, targetKey, resolveColumnInSource) {
1804
1856
  const notifier = db.schemaManager.getChangeNotifier();
1805
- const renamedSchemaLower = renamedSchemaName.toLowerCase();
1806
1857
  for (const table of Array.from(schema.getAllTables())) {
1807
- const updated = rewriteTableForColumnRename(table, renamedSchemaLower, tableName, oldCol, newCol, resolveColumnInSource);
1858
+ const updated = rewriteTableForColumnRename(table, tableName, oldCol, newCol, resolvers, targetKey, resolveColumnInSource);
1808
1859
  if (updated !== table) {
1809
1860
  schema.addTable(updated);
1810
1861
  notifier.notifyChange({
@@ -1816,65 +1867,66 @@ async function propagateColumnRenameInSchema(db, schema, renamedSchemaName, tabl
1816
1867
  });
1817
1868
  }
1818
1869
  }
1819
- if (schema.name.toLowerCase() === renamedSchemaLower) {
1820
- for (const view of Array.from(schema.getAllViews())) {
1821
- // The body walk also descends the trailing `with defaults (…)` clause (now
1822
- // on `selectAst.defaults`): the entry `column` (a base column of the view's
1823
- // FROM table, usually projected away) rewrites via the same scope-aware
1824
- // synthetic probe as a `with inverse` target, and the entry exprs rewrite in
1825
- // the FROM frame — so a clause-only change flips `bodyChanged`. The live
1826
- // `resolveColumnInSource` keeps the walk scope-aware so an unqualified ref
1827
- // inside a defaults-expr subquery that binds a like-named column on its own
1828
- // FROM is not false-captured (the differ's inverse reconcile passes the
1829
- // declared-side resolver for parity).
1830
- const bodyChanged = renameColumnInAst(view.selectAst, tableName, oldCol, newCol, renamedSchemaName, resolveColumnInSource);
1831
- if (bodyChanged) {
1832
- const updatedView = { ...view, sql: astToString(view.selectAst) };
1833
- schema.addView(updatedView);
1834
- // The rewriter mutated `view.selectAst` (including its defaults clause) in
1835
- // place, so `oldObject` shares the rewritten AST (only `sql` differs). No
1836
- // consumer reads `oldObject.selectAst`; mirrors the table loop above (no clone).
1837
- notifier.notifyChange({
1838
- type: 'view_modified',
1839
- schemaName: schema.name,
1840
- objectName: updatedView.name,
1841
- oldObject: view,
1842
- newObject: updatedView,
1843
- });
1844
- }
1870
+ // Bodies owned by this schema resolve under ITS home path, over the pre-mutation
1871
+ // snapshot — same per-schema resolver, and same all-schema scope, as the
1872
+ // table-rename loop.
1873
+ const resolve = resolvers.forHomeSchema(schema.name);
1874
+ for (const view of Array.from(schema.getAllViews())) {
1875
+ // The body walk also descends the trailing `with defaults (…)` clause (now
1876
+ // on `selectAst.defaults`): the entry `column` (a base column of the view's
1877
+ // FROM table, usually projected away) rewrites via the same scope-aware
1878
+ // synthetic probe as a `with inverse` target, and the entry exprs rewrite in
1879
+ // the FROM frame — so a clause-only change flips `bodyChanged`. The live
1880
+ // `resolveColumnInSource` keeps the walk scope-aware so an unqualified ref
1881
+ // inside a defaults-expr subquery that binds a like-named column on its own
1882
+ // FROM is not false-captured (the differ's inverse reconcile passes the
1883
+ // declared-side resolver for parity).
1884
+ const bodyChanged = renameColumnInAst(view.selectAst, tableName, oldCol, newCol, resolve, targetKey, 'none', resolveColumnInSource);
1885
+ if (bodyChanged) {
1886
+ const updatedView = { ...view, sql: astToString(view.selectAst) };
1887
+ schema.addView(updatedView);
1888
+ // The rewriter mutated `view.selectAst` (including its defaults clause) in
1889
+ // place, so `oldObject` shares the rewritten AST (only `sql` differs). No
1890
+ // consumer reads `oldObject.selectAst`; mirrors the table loop above (no clone).
1891
+ notifier.notifyChange({
1892
+ type: 'view_modified',
1893
+ schemaName: schema.name,
1894
+ objectName: updatedView.name,
1895
+ oldObject: view,
1896
+ newObject: updatedView,
1897
+ });
1845
1898
  }
1846
- // Assertions: same in-place body rewrite as plain views (unseeded walker —
1847
- // an assertion body owns its own FROM scopes), plus a regenerated
1848
- // `violationSql`.
1849
- propagateColumnRenameToAssertions(db, schema, renamedSchemaName, tableName, oldCol, newCol, resolveColumnInSource);
1850
- // Materialized views: same in-place body rewrite as plain views, then the
1851
- // MV-specific tail — backing-column rename for a shifted output name,
1852
- // row-time re-registration, staleness discipline (the listener marked every
1853
- // dependent MV stale during the rename's notify; only statement-local
1854
- // staleness is cleared, per the pre-statement snapshot).
1855
- await propagateColumnRenameToMaterializedViews(db, schema, renamedSchemaName, tableName, oldCol, newCol, preStaleMvs, resolveColumnInSource);
1856
1899
  }
1900
+ // Assertions: same in-place body rewrite as plain views (unseeded walker —
1901
+ // an assertion body owns its own FROM scopes), plus a regenerated
1902
+ // `violationSql`.
1903
+ propagateColumnRenameToAssertions(db, schema, tableName, oldCol, newCol, resolve, targetKey, resolveColumnInSource);
1857
1904
  }
1858
- function rewriteTableForColumnRename(table, renamedSchemaLower, tableName, oldCol, newCol, resolveColumnInSource) {
1905
+ function rewriteTableForColumnRename(table, tableName, oldCol, newCol, resolvers, targetKey, resolveColumnInSource) {
1859
1906
  const oldColLower = oldCol.toLowerCase();
1860
- const tableLower = tableName.toLowerCase();
1861
- const isRenamedTable = table.schemaName.toLowerCase() === renamedSchemaLower &&
1862
- table.name.toLowerCase() === tableLower;
1907
+ const resolve = resolvers.forHomeSchema(table.schemaName);
1908
+ // Key comparison, so a same-named table in another schema never takes the
1909
+ // seeded branch.
1910
+ const isRenamedTable = objectRefKey(table.schemaName, table.name) === targetKey;
1863
1911
  let changed = false;
1912
+ // Row-image modes: a CHECK is written-row context wherever it lives — 'own'
1913
+ // when its image IS the renamed table, 'foreign' when it is another table's
1914
+ // (a bare `new.`/`old.` there names THAT table's row, never the renamed one,
1915
+ // even for a table literally called `new`).
1864
1916
  const newChecks = table.checkConstraints.map(cc => {
1865
1917
  const rewrote = isRenamedTable
1866
- ? renameColumnInCheckExpression(cc.expr, tableName, oldCol, newCol, renamedSchemaLower, resolveColumnInSource)
1867
- : renameColumnInAst(cc.expr, tableName, oldCol, newCol, renamedSchemaLower, resolveColumnInSource);
1918
+ ? renameColumnInCheckExpression(cc.expr, tableName, oldCol, newCol, resolve, targetKey, 'own', resolveColumnInSource)
1919
+ : renameColumnInAst(cc.expr, tableName, oldCol, newCol, resolve, targetKey, 'foreign', resolveColumnInSource);
1868
1920
  if (!rewrote)
1869
1921
  return cc;
1870
1922
  changed = true;
1871
1923
  return { ...cc };
1872
1924
  });
1873
1925
  const newFks = (table.foreignKeys ?? []).map(fk => {
1874
- const fkSchemaLower = (fk.referencedSchema ?? table.schemaName).toLowerCase();
1875
- if (fkSchemaLower !== renamedSchemaLower)
1876
- return fk;
1877
- if (fk.referencedTable.toLowerCase() !== tableLower)
1926
+ // An unqualified `referencedTable` binds the CHILD table's own schema
1927
+ // (never the session path — see `assertNoForeignKeyReferencesColumn`),
1928
+ // hence the composed key rather than the resolver.
1929
+ if (objectRefKey(fk.referencedSchema ?? table.schemaName, fk.referencedTable) !== targetKey)
1878
1930
  return fk;
1879
1931
  if (!fk.referencedColumnNames || fk.referencedColumnNames.length === 0)
1880
1932
  return fk;
@@ -1907,10 +1959,12 @@ function rewriteTableForColumnRename(table, renamedSchemaLower, tableName, oldCo
1907
1959
  // expressions above, via `renameColumnInCheckConstraints`). Both use the same
1908
1960
  // idempotent `renameColumnInIndexPredicates`, so this pass then finds nothing naming
1909
1961
  // `oldCol`, `rewrote` is false, and the table is not needlessly re-registered.
1962
+ // Row-image mode 'none' on both arms: a predicate describes rows already
1963
+ // stored, so it has no written-row context regardless of which table owns it.
1910
1964
  const newIndexes = (table.indexes ?? []).map(idx => {
1911
1965
  const rewrote = isRenamedTable
1912
- ? renameColumnInCheckExpression(idx.predicate, tableName, oldCol, newCol, renamedSchemaLower, resolveColumnInSource)
1913
- : renameColumnInAst(idx.predicate, tableName, oldCol, newCol, renamedSchemaLower, resolveColumnInSource);
1966
+ ? renameColumnInCheckExpression(idx.predicate, tableName, oldCol, newCol, resolve, targetKey, 'none', resolveColumnInSource)
1967
+ : renameColumnInAst(idx.predicate, tableName, oldCol, newCol, resolve, targetKey, 'none', resolveColumnInSource);
1914
1968
  if (!rewrote)
1915
1969
  return idx;
1916
1970
  changed = true;
@@ -1929,8 +1983,8 @@ function rewriteTableForColumnRename(table, renamedSchemaLower, tableName, oldCo
1929
1983
  // built and handed back. Flipping `changed` is what re-registers the table and fires
1930
1984
  // `table_modified`, which is all the copies above achieve either.
1931
1985
  const columnsRewritten = isRenamedTable
1932
- ? renameColumnInColumnExpressions(table.columns, tableName, oldCol, newCol, renamedSchemaLower, resolveColumnInSource)
1933
- : rewriteOtherTableColumnExpressions(table.columns, tableName, oldCol, newCol, renamedSchemaLower, resolveColumnInSource);
1986
+ ? renameColumnInColumnExpressions(table.columns, tableName, oldCol, newCol, resolve, targetKey, resolveColumnInSource)
1987
+ : rewriteOtherTableColumnExpressions(table.columns, tableName, oldCol, newCol, resolve, targetKey, resolveColumnInSource);
1934
1988
  if (columnsRewritten)
1935
1989
  changed = true;
1936
1990
  if (!changed)
@@ -1957,11 +2011,14 @@ function rewriteTableForColumnRename(table, renamedSchemaLower, tableName, oldCo
1957
2011
  * keeps this pass in step with the pre-flight persistability probe, which runs the same
1958
2012
  * rewriter with the resolver supplied.
1959
2013
  */
1960
- function rewriteOtherTableColumnExpressions(columns, tableName, oldCol, newCol, renamedSchemaLower, resolveColumnInSource) {
2014
+ function rewriteOtherTableColumnExpressions(columns, tableName, oldCol, newCol, resolve, targetKey, resolveColumnInSource) {
1961
2015
  let changed = false;
1962
2016
  for (const col of columns) {
1963
2017
  for (const expr of [col.defaultValue, col.generatedExpr]) {
1964
- if (expr && renameColumnInAst(expr, tableName, oldCol, newCol, renamedSchemaLower, resolveColumnInSource))
2018
+ // 'foreign': another table's DEFAULT / generated body is written-row
2019
+ // context whose image is THAT table — a bare `new.`/`old.` there names
2020
+ // nothing this rename cares about.
2021
+ if (expr && renameColumnInAst(expr, tableName, oldCol, newCol, resolve, targetKey, 'foreign', resolveColumnInSource))
1965
2022
  changed = true;
1966
2023
  }
1967
2024
  }