@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.
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/dist/postgres/migrate/replication.d.ts.map +1 -1
- package/dist/postgres/migrate/replication.js +2 -1
- package/dist/postgres/migrate/steps.d.ts.map +1 -1
- package/dist/postgres/migrate/steps.js +10 -4
- package/package.json +2 -2
- package/src/postgres/migrate/followups.e2e.test.ts +22 -1
- package/src/postgres/migrate/followups.test.ts +24 -2
- package/src/postgres/migrate/kinds.e2e.test.ts +2 -1
- package/src/postgres/migrate/partition.e2e.test.ts +1 -1
- package/src/postgres/migrate/replication.ts +2 -1
- package/src/postgres/migrate/steps.ts +10 -4
- package/src/postgres/migrate/subscriber.test.ts +2 -0
package/dist/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
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": "
|
|
83
|
+
"composite": "0054f3f742f57903f58e0709691f902f707648664f3d33f542d61c63b1dc3a92"
|
|
84
84
|
}
|
package/dist/manifest.json
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
56
|
-
expect(body).toContain(
|
|
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
|
-
|
|
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 %
|
|
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
|
-
|
|
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
|
-
|
|
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");
|