@intentius/chant-lexicon-sql 0.124.65 → 0.124.66

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "c453c874223d38105a2fc210ed42033b7f29578daa96a4abada2a93c2d148d31",
4
+ "manifest.json": "230288755e61f59691000882709ce99f1ffcc743c0c186fb451c0c9fba9b83a7",
5
5
  "meta.json": "2a75a38ea0fb186f27a59d6b8401d7af0809db5e471769f0259f7c1a4292b858",
6
6
  "types/index.d.ts": "0286ebb367773e84c76818b0f69cb14cff8328fd2f8c65ed87563c8d5815458c",
7
7
  "rules/postgres-templates.ts": "cbbe8b3c3531300ef5f17d596bf9403343d9fde019961436b6af0cdc66e4064a",
@@ -80,5 +80,5 @@
80
80
  "rules/sqlpg125.ts": "cc7411c57c525613dc720ba00e986bbc4e5a84b8b0bcfa7a6ce0d058f039f025",
81
81
  "rules/sqlpg126.ts": "d57b82a5842273876510131d67bf4418cbd61eff821e245edebc644dafd502bb"
82
82
  },
83
- "composite": "664a0e41dcfc6a81fa3039ea6351edc2ac9cba8b5b03d754c330af7da455be62"
83
+ "composite": "0054f3f742f57903f58e0709691f902f707648664f3d33f542d61c63b1dc3a92"
84
84
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sql",
3
- "version": "0.124.65",
3
+ "version": "0.124.66",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "SQL",
6
6
  "intrinsics": [],
@@ -1 +1 @@
1
- {"version":3,"file":"replication.d.ts","sourceRoot":"","sources":["../../../src/postgres/migrate/replication.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,uBAAuB,EAAE,mBAA+D,CAAC;AAEtG,sFAAsF;AACtF,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,UAAU;IACzB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,kFAAkF;AAClF,wBAAsB,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAO9F;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,EACrC,KAAK,EAAE,mBAAmB,EAC1B,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GACjJ,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAanK;AAgBD,8EAA8E;AAC9E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAarJ;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,MAAM,CAQlG"}
1
+ {"version":3,"file":"replication.d.ts","sourceRoot":"","sources":["../../../src/postgres/migrate/replication.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,uBAAuB,EAAE,mBAA+D,CAAC;AAEtG,sFAAsF;AACtF,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,UAAU;IACzB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,kFAAkF;AAClF,wBAAsB,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAO9F;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,EACrC,KAAK,EAAE,mBAAmB,EAC1B,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GACjJ,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAanK;AAgBD,8EAA8E;AAC9E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAcrJ;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,MAAM,CAQlG"}
@@ -140,7 +140,8 @@ function sleepFor(ms, signal) {
140
140
  */
141
141
  export async function subscriptionsOf(client, schema, table, major) {
142
142
  const rel = "pg_catalog.to_regclass(pg_catalog.quote_ident($1) || '.' || pg_catalog.quote_ident($2))";
143
- const tables = major >= 12 ? `SELECT relid FROM pg_catalog.pg_partition_tree(${rel})` : `SELECT ${rel}::oid AS relid`;
143
+ // pg_partition_tree lists nothing for a table that is not partitioned, so the table itself is always one of them.
144
+ const tables = major >= 12 ? `SELECT ${rel}::oid AS relid UNION SELECT relid FROM pg_catalog.pg_partition_tree(${rel})` : `SELECT ${rel}::oid AS relid`;
144
145
  const rows = await client.query(`SELECT DISTINCT s.subname, s.subenabled
145
146
  FROM pg_catalog.pg_subscription_rel sr
146
147
  JOIN pg_catalog.pg_subscription s ON s.oid = sr.srsubid
@@ -1 +1 @@
1
- {"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../../../src/postgres/migrate/steps.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../../../src/postgres/migrate/steps.ts"],"names":[],"mappings":"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"}
@@ -159,16 +159,18 @@ export function dualWriteBody(o) {
159
159
  const src = `NEW.${col(n.source)}`;
160
160
  if (n.change === "rename" && o.reverse !== undefined) {
161
161
  // A rename with a type change: a writer of the old name has `expression` applied, a writer of the new name `reverse`, each over the row as it is.
162
+ // An update that sets the new column to what `expression` already gives (the backfill's own UPDATE) leaves the old one alone, so a
163
+ // lossy `reverse` never rewrites a row nobody wrote by its new name, and the verification still sees the old values to check it against.
162
164
  const fwd = `(SELECT ${o.expression} FROM (SELECT NEW.*) AS ${col(n.table)})`;
163
165
  const back = `(SELECT ${o.reverse} FROM (SELECT NEW.*) AS ${col(n.table)})`;
164
166
  return [
165
167
  `BEGIN`,
166
168
  ` IF TG_OP = 'INSERT' THEN`,
167
169
  ` IF ${nw} IS NULL THEN ${nw} := ${fwd}; ELSE ${src} := ${back}; END IF;`,
168
- ` ELSIF ${nw} IS DISTINCT FROM OLD.${col(n.newColumn)} THEN`,
169
- ` ${src} := ${back};`,
170
- ` ELSE`,
170
+ ` ELSIF ${nw} IS NOT DISTINCT FROM OLD.${col(n.newColumn)} THEN`,
171
171
  ` ${nw} := ${fwd};`,
172
+ ` ELSIF ${nw} IS DISTINCT FROM ${fwd} THEN`,
173
+ ` ${src} := ${back};`,
172
174
  ` END IF;`,
173
175
  ` RETURN NEW;`,
174
176
  `END`,
@@ -388,7 +390,11 @@ function sequenceStatements(o, state, at = "switch") {
388
390
  return { before: [], after: [] };
389
391
  if (at === "contract" && seq.kind === "serial") {
390
392
  // The sequence goes to the new column before the old one is dropped, which would drop it; the default is set after.
391
- return { before: [`ALTER SEQUENCE ${seq.ident} OWNED BY ${t}.${col(n.column)}`], after: [] };
393
+ // A sequence with the name Postgres gives a serial's (<table>_<old>_seq) then takes the new column's, which the declared
394
+ // `serial` names: under the old name the column reads back as an integer with a sequence of its own, and the plan drops it.
395
+ const renamed = `${n.table}_${n.column}_seq`;
396
+ const rename = seq.name === `${n.table}_${n.source}_seq` && Buffer.byteLength(renamed) <= 63 ? [`ALTER SEQUENCE ${seq.ident} RENAME TO ${col(renamed)}`] : [];
397
+ return { before: [`ALTER SEQUENCE ${seq.ident} OWNED BY ${t}.${col(n.column)}`], after: rename };
392
398
  }
393
399
  if (seq.kind === "identity") {
394
400
  if (!state)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-sql",
3
- "version": "0.124.65",
3
+ "version": "0.124.66",
4
4
  "description": "SQL lexicon for chant — database schema as typed declarations, one dialect at a time; ClickHouse first, with types read from a pinned server's catalog",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -72,6 +72,6 @@
72
72
  "typescript": "^5.9.3"
73
73
  },
74
74
  "peerDependencies": {
75
- "@intentius/chant": "^0.124.65"
75
+ "@intentius/chant": "^0.124.66"
76
76
  }
77
77
  }
@@ -150,7 +150,7 @@ describe.skipIf(!enabled)("a rename of a serial column", () => {
150
150
  expect(await one("SELECT n AS n FROM sq.items WHERE id = 1002")).toEqual({ n: 7000 });
151
151
  });
152
152
  expect(runs.map((r) => r.status)).toEqual(["gated", "gated", "ok"]);
153
- expect(await one("SELECT pg_catalog.pg_get_serial_sequence('sq.items', 'num') AS seq")).toEqual({ seq: "sq.items_n_seq" });
153
+ expect(await one("SELECT pg_catalog.pg_get_serial_sequence('sq.items', 'num') AS seq")).toEqual({ seq: "sq.items_num_seq" });
154
154
  const next = await one<{ id: number; num: number }>("INSERT INTO sq.items (id) VALUES (2000) RETURNING id::int AS id, num");
155
155
  expect(next.num).toBeGreaterThan(300);
156
156
  expect((await plan("sq-v2.json")).changes).toEqual([]);
@@ -199,6 +199,8 @@ describe.skipIf(!enabled)("a rename with a type change", () => {
199
199
  expect(bad).toBeInstanceOf(OpRunFailure);
200
200
  expect((bad as OpRunFailure).result.records.find((x) => x.fn === "postgresMigrationVerify")?.error).toMatch(/must give the old value back/);
201
201
  expect(await one("SELECT count(*)::int AS n FROM pg_attribute WHERE attrelid = 'rt.people'::regclass AND attname = 'age' AND NOT attisdropped")).toEqual({ n: 0 });
202
+ // The backfill wrote the new column only: the old one is as it was, not rewritten through the wrong reverse.
203
+ expect(await one("SELECT count(*)::int AS n FROM rt.people WHERE age_text IS DISTINCT FROM (id % 90)::text")).toEqual({ n: 0 });
202
204
 
203
205
  const runs = await runToEnd(config({ name: "migrate-people-age", table: "rt.people", column: "age", output: "rt-v2.json", using: "CAST(age_text AS integer)", reverse: "CAST(age AS text)" }), async () => {
204
206
  await admin!.query("INSERT INTO rt.people (id, age_text) VALUES (1001, '41')"); // the old name
@@ -215,4 +217,23 @@ describe.skipIf(!enabled)("a rename with a type change", () => {
215
217
  expect(await admin!.query("SELECT attname FROM pg_attribute WHERE attrelid = 'rt.people'::regclass AND attnum > 0 AND NOT attisdropped ORDER BY attnum")).toEqual([{ attname: "id" }, { attname: "age" }]);
216
218
  expect((await plan("rt-v2.json")).changes).toEqual([]);
217
219
  }, 300_000);
220
+
221
+ test("a reverse that loses something ('007' -> 7 -> '7') fails the verification and leaves the old column as it was", async () => {
222
+ const LR = schemaObj("lr");
223
+ const codes = (column: string, previously?: string) => keyed("codes", "lr", column, previously);
224
+ await apply(writeBuild("lr-v1.json", [LR, codes("code_text text NOT NULL")]));
225
+ await admin!.query("INSERT INTO lr.codes VALUES (1, '007'), (2, '42')");
226
+ writeBuild("lr-v2.json", [LR, codes("code integer NOT NULL", "code_text")]);
227
+
228
+ const lossy = await runMigrationOp(config({ name: "migrate-codes-code", table: "lr.codes", column: "code", output: "lr-v2.json", using: "CAST(code_text AS integer)", reverse: "CAST(code AS text)" }), new ApprovingLedger().port, deps).then(
229
+ () => undefined,
230
+ (e: unknown) => e,
231
+ );
232
+ expect(lossy).toBeInstanceOf(OpRunFailure);
233
+ expect((lossy as OpRunFailure).result.records.find((x) => x.fn === "postgresMigrationVerify")?.error).toMatch(/1 of 2 row\(s\) have code_text different/);
234
+ expect(await admin!.query("SELECT id::int AS id, code_text FROM lr.codes ORDER BY id")).toEqual([
235
+ { id: 1, code_text: "007" },
236
+ { id: 2, code_text: "42" },
237
+ ]);
238
+ }, 300_000);
218
239
  });
@@ -52,8 +52,17 @@ describe("a rename with a type change", () => {
52
52
  test("a writer of the old name has the expression applied, a writer of the new name the reverse", () => {
53
53
  const body = dualWriteBody(o);
54
54
  expect(body).toContain("IF NEW.age IS NULL THEN NEW.age := (SELECT CAST(age_text AS integer) FROM (SELECT NEW.*) AS users); ELSE NEW.age_text := (SELECT CAST(age AS text) FROM (SELECT NEW.*) AS users); END IF;");
55
- expect(body).toContain("ELSIF NEW.age IS DISTINCT FROM OLD.age THEN\n NEW.age_text := (SELECT CAST(age AS text) FROM (SELECT NEW.*) AS users);");
56
- expect(body).toContain("ELSE\n NEW.age := (SELECT CAST(age_text AS integer) FROM (SELECT NEW.*) AS users);");
55
+ expect(body).toContain("ELSIF NEW.age IS NOT DISTINCT FROM OLD.age THEN\n NEW.age := (SELECT CAST(age_text AS integer) FROM (SELECT NEW.*) AS users);");
56
+ expect(body).toContain(
57
+ "ELSIF NEW.age IS DISTINCT FROM (SELECT CAST(age_text AS integer) FROM (SELECT NEW.*) AS users) THEN\n NEW.age_text := (SELECT CAST(age AS text) FROM (SELECT NEW.*) AS users);\n END IF;",
58
+ );
59
+ });
60
+
61
+ test("an update that sets the new column to what the expression gives (the backfill) leaves the old column alone", () => {
62
+ // Were the old column rewritten from reverse here, a lossy pair ('007' -> 7 -> '7') would change rows nobody wrote, and hide itself from the verification.
63
+ const body = dualWriteBody(o);
64
+ expect(body).not.toMatch(/ELSIF NEW\.age IS DISTINCT FROM OLD\.age THEN/);
65
+ expect(body.match(/NEW\.age_text :=/g)).toHaveLength(2);
57
66
  });
58
67
 
59
68
  test("a plain rename's body is unchanged", () => {
@@ -96,6 +105,19 @@ describe("the contract of a rename that kept its default", () => {
96
105
  ]);
97
106
  });
98
107
 
108
+ test("a serial's sequence named as Postgres names it takes the new column's name, after the default is set", () => {
109
+ const o = observation({
110
+ column: { name: "login", type: "serial" },
111
+ old: { attnum: 2, name: "email", type: "integer", notNull: true, default: "nextval('app.users_email_seq'::regclass)", generated: false, identity: false },
112
+ sequence: { kind: "serial", schema: "app", name: "users_email_seq", ident: "app.users_email_seq" },
113
+ });
114
+ expect(contractStatements(o).slice(-3)).toEqual([
115
+ "ALTER TABLE app.users DROP COLUMN email",
116
+ "ALTER TABLE app.users ALTER COLUMN login SET DEFAULT nextval('app.users_email_seq'::regclass)",
117
+ "ALTER SEQUENCE app.users_email_seq RENAME TO users_login_seq",
118
+ ]);
119
+ });
120
+
99
121
  test("an identity moves to the new column under its sequence's name and carries on where the old one stood", () => {
100
122
  const o = observation({
101
123
  column: { name: "login", type: "integer", generated: { kind: "identity", always: true, options: "(CACHE 5)" } },
@@ -192,7 +192,8 @@ describe.skipIf(!enabled)("what the Op refuses among the rest", () => {
192
192
  expect(await refusal("rf.parent", "v", "rf-v2.json")).toMatch(/^rf\.parent has inheritance children \(rf\.child\)\. The Op does not migrate inheritance trees: a write to a child table does not fire the parent's dual-write trigger/);
193
193
  expect(await refusal("rf.parted", "v", "rf-v2.json")).toMatch(/unique constraint parted_v_key on rf\.parted: on a partitioned table a key cannot be attached from an index built CONCURRENTLY/);
194
194
  expect(await refusal("rf.gen", "g", "rf-v2.json")).toMatch(/^rf\.gen\.g is a generated column\. There is no expand and contract for one/);
195
- expect(await refusal("rf.ident", "key", "rf-v2.json")).toMatch(/sequence rf\.ident_id_seq gives the column its values \(an identity column\); during a rename/);
195
+ // A renamed identity is migrated with defaultAtContract (#3331); without it the Op refuses and says so.
196
+ expect(await refusal("rf.ident", "key", "rf-v2.json")).toMatch(/^rf\.ident: id has a default \(identity\)\. During a rename both columns are written.*Set defaultAtContract: true/s);
196
197
 
197
198
  await admin!.query("ALTER TABLE rf.parted DROP CONSTRAINT parted_v_key");
198
199
  writeBuild("rf-v3.json", [RF, parted("integer", "v"), p1]);
@@ -79,7 +79,7 @@ describe.skipIf(!enabled)("a plain and a partial unique index on a partitioned t
79
79
 
80
80
  test("each partition's index is built and attached, and the partitioned index takes its declared name", async () => {
81
81
  await apply(writeBuild("pi-v1.json", objects("text", "amount")));
82
- await admin!.query("INSERT INTO pi.events SELECT g, DATE '2025-01-01' + (g % 900), (g % 90) || '.5' FROM generate_series(1, 1500) g");
82
+ await admin!.query("INSERT INTO pi.events SELECT g, DATE '2025-01-01' + (g % 800), (g % 90) || '.5' FROM generate_series(1, 1500) g");
83
83
  writeBuild("pi-v2.json", objects("numeric(10,2)", "amount"));
84
84
 
85
85
  const ledger = new ApprovingLedger();
@@ -192,7 +192,8 @@ export interface SubscriptionHit {
192
192
  */
193
193
  export async function subscriptionsOf(client: Pick<PostgresClient, "query">, schema: string, table: string, major: number): Promise<SubscriptionHit[]> {
194
194
  const rel = "pg_catalog.to_regclass(pg_catalog.quote_ident($1) || '.' || pg_catalog.quote_ident($2))";
195
- const tables = major >= 12 ? `SELECT relid FROM pg_catalog.pg_partition_tree(${rel})` : `SELECT ${rel}::oid AS relid`;
195
+ // pg_partition_tree lists nothing for a table that is not partitioned, so the table itself is always one of them.
196
+ const tables = major >= 12 ? `SELECT ${rel}::oid AS relid UNION SELECT relid FROM pg_catalog.pg_partition_tree(${rel})` : `SELECT ${rel}::oid AS relid`;
196
197
  const rows = await client.query<{ subname: string; subenabled: boolean }>(
197
198
  `SELECT DISTINCT s.subname, s.subenabled
198
199
  FROM pg_catalog.pg_subscription_rel sr
@@ -223,16 +223,18 @@ export function dualWriteBody(o: Pick<MigrationObservation, "names" | "expressio
223
223
  const src = `NEW.${col(n.source)}`;
224
224
  if (n.change === "rename" && o.reverse !== undefined) {
225
225
  // A rename with a type change: a writer of the old name has `expression` applied, a writer of the new name `reverse`, each over the row as it is.
226
+ // An update that sets the new column to what `expression` already gives (the backfill's own UPDATE) leaves the old one alone, so a
227
+ // lossy `reverse` never rewrites a row nobody wrote by its new name, and the verification still sees the old values to check it against.
226
228
  const fwd = `(SELECT ${o.expression} FROM (SELECT NEW.*) AS ${col(n.table)})`;
227
229
  const back = `(SELECT ${o.reverse} FROM (SELECT NEW.*) AS ${col(n.table)})`;
228
230
  return [
229
231
  `BEGIN`,
230
232
  ` IF TG_OP = 'INSERT' THEN`,
231
233
  ` IF ${nw} IS NULL THEN ${nw} := ${fwd}; ELSE ${src} := ${back}; END IF;`,
232
- ` ELSIF ${nw} IS DISTINCT FROM OLD.${col(n.newColumn)} THEN`,
233
- ` ${src} := ${back};`,
234
- ` ELSE`,
234
+ ` ELSIF ${nw} IS NOT DISTINCT FROM OLD.${col(n.newColumn)} THEN`,
235
235
  ` ${nw} := ${fwd};`,
236
+ ` ELSIF ${nw} IS DISTINCT FROM ${fwd} THEN`,
237
+ ` ${src} := ${back};`,
236
238
  ` END IF;`,
237
239
  ` RETURN NEW;`,
238
240
  `END`,
@@ -487,7 +489,11 @@ function sequenceStatements(o: MigrationObservation, state: SequenceState | unde
487
489
  if (!seq || n.change !== (at === "switch" ? "type" : "rename")) return { before: [], after: [] };
488
490
  if (at === "contract" && seq.kind === "serial") {
489
491
  // The sequence goes to the new column before the old one is dropped, which would drop it; the default is set after.
490
- return { before: [`ALTER SEQUENCE ${seq.ident} OWNED BY ${t}.${col(n.column)}`], after: [] };
492
+ // A sequence with the name Postgres gives a serial's (<table>_<old>_seq) then takes the new column's, which the declared
493
+ // `serial` names: under the old name the column reads back as an integer with a sequence of its own, and the plan drops it.
494
+ const renamed = `${n.table}_${n.column}_seq`;
495
+ const rename = seq.name === `${n.table}_${n.source}_seq` && Buffer.byteLength(renamed) <= 63 ? [`ALTER SEQUENCE ${seq.ident} RENAME TO ${col(renamed)}`] : [];
496
+ return { before: [`ALTER SEQUENCE ${seq.ident} OWNED BY ${t}.${col(n.column)}`], after: rename };
491
497
  }
492
498
  if (seq.kind === "identity") {
493
499
  if (!state) throw new Error(`${n.key}: the ${at} moves the identity of ${n.source} and needs its sequence's state, read under the switch's lock`);
@@ -33,6 +33,8 @@ describe("subscriptionsOf", () => {
33
33
  const now = fake([]);
34
34
  await subscriptionsOf(now.client, "app", "events", 18);
35
35
  expect(now.calls[0]!.sql).toContain("pg_partition_tree");
36
+ // pg_partition_tree lists nothing for a plain table, so the table itself is matched too.
37
+ expect(now.calls[0]!.sql).toMatch(/::oid AS relid UNION SELECT relid FROM pg_catalog\.pg_partition_tree/);
36
38
  const old = fake([]);
37
39
  await subscriptionsOf(old.client, "app", "events", 11);
38
40
  expect(old.calls[0]!.sql).not.toContain("pg_partition_tree");