@intentius/chant-lexicon-sql 0.124.45 → 0.124.48
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/change-set.d.ts +1 -1
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +2 -1
- package/dist/clickhouse/apply/statements.d.ts +9 -0
- package/dist/clickhouse/apply/statements.d.ts.map +1 -1
- package/dist/clickhouse/apply/statements.js +24 -0
- package/dist/clickhouse/import/live-export.d.ts +7 -3
- package/dist/clickhouse/import/live-export.d.ts.map +1 -1
- package/dist/clickhouse/import/live-export.js +21 -5
- package/dist/clickhouse/live/named-collections.d.ts +27 -0
- package/dist/clickhouse/live/named-collections.d.ts.map +1 -0
- package/dist/clickhouse/live/named-collections.js +53 -0
- package/dist/clickhouse/live/undeclarable.d.ts +15 -3
- package/dist/clickhouse/live/undeclarable.d.ts.map +1 -1
- package/dist/clickhouse/live/undeclarable.js +18 -4
- package/dist/clickhouse/named-collections.d.ts +83 -0
- package/dist/clickhouse/named-collections.d.ts.map +1 -0
- package/dist/clickhouse/named-collections.js +203 -0
- package/dist/clickhouse/parser.d.ts.map +1 -1
- package/dist/clickhouse/parser.js +1 -1
- package/dist/clickhouse/plan/commands.d.ts +2 -1
- package/dist/clickhouse/plan/commands.d.ts.map +1 -1
- package/dist/clickhouse/plan/commands.js +17 -2
- package/dist/clickhouse/plan/diff.d.ts +15 -0
- package/dist/clickhouse/plan/diff.d.ts.map +1 -1
- package/dist/clickhouse/plan/diff.js +43 -1
- package/dist/clickhouse/plan/disruption.d.ts.map +1 -1
- package/dist/clickhouse/plan/disruption.js +5 -0
- package/dist/clickhouse/plan/rebuild-handoff.d.ts.map +1 -1
- package/dist/clickhouse/plan/rebuild-handoff.js +4 -0
- package/dist/clickhouse/plan/report.d.ts.map +1 -1
- package/dist/clickhouse/plan/report.js +6 -1
- package/dist/clickhouse/plan/rules.d.ts +5 -1
- package/dist/clickhouse/plan/rules.d.ts.map +1 -1
- package/dist/clickhouse/plan/rules.js +7 -3
- package/dist/clickhouse/plan/stream.d.ts +40 -0
- package/dist/clickhouse/plan/stream.d.ts.map +1 -0
- package/dist/clickhouse/plan/stream.js +107 -0
- package/dist/clickhouse/rebuild/observe.d.ts +3 -1
- package/dist/clickhouse/rebuild/observe.d.ts.map +1 -1
- package/dist/clickhouse/rebuild/observe.js +14 -1
- package/dist/clickhouse/review-catalog.d.ts +213 -0
- package/dist/clickhouse/review-catalog.d.ts.map +1 -0
- package/dist/clickhouse/review-catalog.js +330 -0
- package/dist/codegen/classifier-page.d.ts.map +1 -1
- package/dist/codegen/classifier-page.js +21 -4
- package/dist/codegen/clickhouse-module.d.ts.map +1 -1
- package/dist/codegen/clickhouse-module.js +3 -0
- package/dist/codegen/coverage-page.d.ts.map +1 -1
- package/dist/codegen/coverage-page.js +5 -3
- package/dist/codegen/docs.js +1 -1
- package/dist/codegen/postgres-classifier-page.js +1 -1
- package/dist/codegen/registry.d.ts.map +1 -1
- package/dist/codegen/registry.js +5 -0
- package/dist/composites/catalog.d.ts.map +1 -1
- package/dist/composites/catalog.js +100 -0
- package/dist/composites/clickhouse.d.ts +2 -0
- package/dist/composites/clickhouse.d.ts.map +1 -1
- package/dist/composites/clickhouse.js +2 -0
- package/dist/composites/otel-tables.d.ts +100 -0
- package/dist/composites/otel-tables.d.ts.map +1 -0
- package/dist/composites/otel-tables.js +282 -0
- package/dist/composites/stream-ingest.d.ts +63 -0
- package/dist/composites/stream-ingest.d.ts.map +1 -0
- package/dist/composites/stream-ingest.js +39 -0
- package/dist/coverage/clickhouse.json +1 -1
- package/dist/coverage/postgres.json +7 -7
- package/dist/coverage.d.ts +16 -6
- package/dist/coverage.d.ts.map +1 -1
- package/dist/coverage.js +10 -5
- package/dist/drizzle-command.d.ts +17 -0
- package/dist/drizzle-command.d.ts.map +1 -0
- package/dist/drizzle-command.js +91 -0
- package/dist/drizzle.d.ts +70 -0
- package/dist/drizzle.d.ts.map +1 -0
- package/dist/drizzle.js +684 -0
- package/dist/files/clickhouse.d.ts.map +1 -1
- package/dist/files/clickhouse.js +8 -1
- package/dist/files/common.d.ts +13 -0
- package/dist/files/common.d.ts.map +1 -1
- package/dist/files/common.js +5 -0
- package/dist/files/postgres.js +12 -2
- package/dist/generated/clickhouse.d.ts +2 -0
- package/dist/generated/clickhouse.d.ts.map +1 -1
- package/dist/generated/clickhouse.js +2 -0
- package/dist/import-parser.d.ts +21 -1
- package/dist/import-parser.d.ts.map +1 -1
- package/dist/import-parser.js +79 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/integrity.json +6 -5
- package/dist/lint/post-synth/audit-entries.d.ts.map +1 -1
- package/dist/lint/post-synth/audit-entries.js +1 -0
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/post-synth/index.js +2 -0
- package/dist/lint/post-synth/sqlch128.d.ts +18 -0
- package/dist/lint/post-synth/sqlch128.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch128.js +222 -0
- package/dist/lint/rules/postgres-templates.js +2 -2
- package/dist/lsp/postgres-template.d.ts.map +1 -1
- package/dist/lsp/postgres-template.js +11 -0
- package/dist/manifest.json +1 -1
- package/dist/mcp/postgres.js +1 -1
- package/dist/meta.json +25 -0
- package/dist/migrate/from-postgres/detect.d.ts +4 -0
- package/dist/migrate/from-postgres/detect.d.ts.map +1 -0
- package/dist/migrate/from-postgres/detect.js +7 -0
- package/dist/migrate/from-postgres/emit.d.ts +26 -0
- package/dist/migrate/from-postgres/emit.d.ts.map +1 -0
- package/dist/migrate/from-postgres/emit.js +86 -0
- package/dist/migrate/from-postgres/index.d.ts +51 -0
- package/dist/migrate/from-postgres/index.d.ts.map +1 -0
- package/dist/migrate/from-postgres/index.js +115 -0
- package/dist/migrate/from-postgres/translate.d.ts +73 -0
- package/dist/migrate/from-postgres/translate.d.ts.map +1 -0
- package/dist/migrate/from-postgres/translate.js +261 -0
- package/dist/migrate/from-postgres/types.d.ts +51 -0
- package/dist/migrate/from-postgres/types.d.ts.map +1 -0
- package/dist/migrate/from-postgres/types.js +211 -0
- package/dist/migration-replay.d.ts +73 -0
- package/dist/migration-replay.d.ts.map +1 -0
- package/dist/migration-replay.js +294 -0
- package/dist/okf/index.md +6 -0
- package/dist/okf/rules/SQLCH128.md +11 -0
- package/dist/okf/types/PostgresForeignDataWrapper.md +9 -0
- package/dist/okf/types/PostgresForeignServer.md +9 -0
- package/dist/okf/types/PostgresOperator.md +9 -0
- package/dist/okf/types/PostgresPublication.md +9 -0
- package/dist/okf/types/PostgresStatistics.md +9 -0
- package/dist/op/activities/postgres-migration.d.ts.map +1 -1
- package/dist/op/activities/postgres-migration.js +4 -0
- package/dist/op/activity-contracts.d.ts +20 -0
- package/dist/op/activity-contracts.d.ts.map +1 -1
- package/dist/op/activity-contracts.js +2 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +36 -2
- package/dist/postgres/apply/apply.js +8 -1
- package/dist/postgres/apply/statements.d.ts.map +1 -1
- package/dist/postgres/apply/statements.js +87 -2
- package/dist/postgres/constraint-names.d.ts +30 -0
- package/dist/postgres/constraint-names.d.ts.map +1 -0
- package/dist/postgres/constraint-names.js +72 -0
- package/dist/postgres/entities.d.ts +110 -1
- package/dist/postgres/entities.d.ts.map +1 -1
- package/dist/postgres/entities.js +146 -0
- package/dist/postgres/entity-types.d.ts +5 -0
- package/dist/postgres/entity-types.d.ts.map +1 -1
- package/dist/postgres/entity-types.js +5 -0
- package/dist/postgres/import/generator.d.ts.map +1 -1
- package/dist/postgres/import/generator.js +50 -2
- package/dist/postgres/import/live-export.d.ts.map +1 -1
- package/dist/postgres/import/live-export.js +2 -0
- package/dist/postgres/live/catalog-kinds.d.ts +14 -0
- package/dist/postgres/live/catalog-kinds.d.ts.map +1 -1
- package/dist/postgres/live/catalog-kinds.js +206 -0
- package/dist/postgres/live/catalog.d.ts +2 -0
- package/dist/postgres/live/catalog.d.ts.map +1 -1
- package/dist/postgres/live/catalog.js +3 -1
- package/dist/postgres/live/describe-resources.d.ts.map +1 -1
- package/dist/postgres/live/describe-resources.js +10 -2
- package/dist/postgres/migrate/backfill.d.ts +2 -0
- package/dist/postgres/migrate/backfill.d.ts.map +1 -1
- package/dist/postgres/migrate/backfill.js +7 -1
- package/dist/postgres/migrate/carry.d.ts +45 -1
- package/dist/postgres/migrate/carry.d.ts.map +1 -1
- package/dist/postgres/migrate/carry.js +72 -8
- package/dist/postgres/migrate/observe.d.ts +28 -4
- package/dist/postgres/migrate/observe.d.ts.map +1 -1
- package/dist/postgres/migrate/observe.js +41 -12
- package/dist/postgres/migrate/op.d.ts +26 -1
- package/dist/postgres/migrate/op.d.ts.map +1 -1
- package/dist/postgres/migrate/op.js +3 -1
- package/dist/postgres/migrate/steps.d.ts +35 -2
- package/dist/postgres/migrate/steps.d.ts.map +1 -1
- package/dist/postgres/migrate/steps.js +158 -12
- package/dist/postgres/parser.d.ts +72 -1
- package/dist/postgres/parser.d.ts.map +1 -1
- package/dist/postgres/parser.js +194 -2
- package/dist/postgres/plan/deep.d.ts.map +1 -1
- package/dist/postgres/plan/deep.js +29 -1
- package/dist/postgres/plan/diff.d.ts.map +1 -1
- package/dist/postgres/plan/diff.js +39 -1
- package/dist/postgres/plan/normalize.d.ts +17 -2
- package/dist/postgres/plan/normalize.d.ts.map +1 -1
- package/dist/postgres/plan/normalize.js +109 -1
- package/dist/postgres/plan/rules.d.ts +1 -0
- package/dist/postgres/plan/rules.d.ts.map +1 -1
- package/dist/postgres/plan/rules.js +3 -2
- package/dist/postgres/plan/schema.js +1 -1
- package/dist/postgres/secret-options.d.ts +10 -0
- package/dist/postgres/secret-options.d.ts.map +1 -0
- package/dist/postgres/secret-options.js +9 -0
- package/dist/postgres/testing/roundtrip-schema.d.ts +3 -2
- package/dist/postgres/testing/roundtrip-schema.d.ts.map +1 -1
- package/dist/postgres/testing/roundtrip-schema.js +13 -1
- package/dist/postgres.d.ts +1 -1
- package/dist/postgres.d.ts.map +1 -1
- package/dist/postgres.js +1 -1
- package/dist/rules/audit-entries.ts +1 -0
- package/dist/rules/postgres-templates.ts +2 -2
- package/dist/rules/sqlch128.ts +230 -0
- package/dist/serializer.d.ts +5 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/serializer.js +13 -2
- package/dist/sql-types-command.d.ts +13 -0
- package/dist/sql-types-command.d.ts.map +1 -1
- package/dist/sql-types-command.js +31 -16
- package/dist/sql-types.d.ts +22 -0
- package/dist/sql-types.d.ts.map +1 -1
- package/dist/sql-types.js +10 -6
- package/dist/sqlserver/lexer.d.ts +37 -0
- package/dist/sqlserver/lexer.d.ts.map +1 -0
- package/dist/sqlserver/lexer.js +254 -0
- package/dist/sqlserver/parse.d.ts +185 -0
- package/dist/sqlserver/parse.d.ts.map +1 -0
- package/dist/sqlserver/parse.js +767 -0
- package/dist/sqlserver/translate.d.ts +34 -0
- package/dist/sqlserver/translate.d.ts.map +1 -0
- package/dist/sqlserver/translate.js +495 -0
- package/dist/sqlserver/types.d.ts +44 -0
- package/dist/sqlserver/types.d.ts.map +1 -0
- package/dist/sqlserver/types.js +133 -0
- package/dist/sqlserver/validate.d.ts +31 -0
- package/dist/sqlserver/validate.d.ts.map +1 -0
- package/dist/sqlserver/validate.js +67 -0
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +5 -0
- package/package.json +2 -2
- package/src/change-set.ts +2 -1
- package/src/clickhouse/apply/statements.ts +25 -0
- package/src/clickhouse/import/live-export.ts +20 -5
- package/src/clickhouse/live/named-collections.e2e.test.ts +88 -0
- package/src/clickhouse/live/named-collections.ts +61 -0
- package/src/clickhouse/live/undeclarable.e2e.test.ts +5 -3
- package/src/clickhouse/live/undeclarable.ts +20 -4
- package/src/clickhouse/named-collections.test.ts +187 -0
- package/src/clickhouse/named-collections.ts +224 -0
- package/src/clickhouse/parser.ts +2 -1
- package/src/clickhouse/plan/commands.ts +17 -2
- package/src/clickhouse/plan/diff.ts +57 -1
- package/src/clickhouse/plan/disruption.ts +5 -0
- package/src/clickhouse/plan/rebuild-handoff.ts +3 -0
- package/src/clickhouse/plan/report.ts +6 -1
- package/src/clickhouse/plan/rules.ts +14 -4
- package/src/clickhouse/plan/stream-s3queue.e2e.test.ts +148 -0
- package/src/clickhouse/plan/stream.test.ts +237 -0
- package/src/clickhouse/plan/stream.ts +111 -0
- package/src/clickhouse/rebuild/observe.ts +15 -1
- package/src/clickhouse/review-catalog.test.ts +181 -0
- package/src/clickhouse/review-catalog.ts +489 -0
- package/src/codegen/classifier-page.ts +21 -4
- package/src/codegen/clickhouse-module.ts +3 -0
- package/src/codegen/coverage-page.ts +5 -3
- package/src/codegen/docs.ts +1 -1
- package/src/codegen/postgres-classifier-page.ts +1 -1
- package/src/codegen/registry.ts +5 -0
- package/src/composites/catalog.test.ts +6 -1
- package/src/composites/catalog.ts +100 -0
- package/src/composites/clickhouse.ts +2 -0
- package/src/composites/composites.test.ts +1 -1
- package/src/composites/otel-tables.test.ts +118 -0
- package/src/composites/otel-tables.ts +339 -0
- package/src/composites/stream-ingest.test.ts +114 -0
- package/src/composites/stream-ingest.ts +82 -0
- package/src/core/undeclarable.test.ts +6 -5
- package/src/coverage/clickhouse.json +1 -1
- package/src/coverage/postgres.json +7 -7
- package/src/coverage.test.ts +27 -2
- package/src/coverage.ts +18 -7
- package/src/drizzle-command.ts +94 -0
- package/src/drizzle-kit.e2e.test.ts +89 -0
- package/src/drizzle-types.e2e.test.ts +67 -0
- package/src/drizzle.test.ts +358 -0
- package/src/drizzle.ts +737 -0
- package/src/files/clickhouse.ts +8 -1
- package/src/files/common.ts +14 -1
- package/src/files/postgres.ts +12 -2
- package/src/generated/clickhouse.ts +3 -0
- package/src/generated/lexicon-sql.json +25 -0
- package/src/import-parser.sqlserver.test.ts +92 -0
- package/src/import-parser.ts +79 -5
- package/src/index.ts +1 -1
- package/src/lint/post-synth/audit-entries.ts +1 -0
- package/src/lint/post-synth/index.ts +2 -0
- package/src/lint/post-synth/sqlch128.test.ts +107 -0
- package/src/lint/post-synth/sqlch128.ts +230 -0
- package/src/lint/rules/postgres-templates.ts +2 -2
- package/src/lsp/postgres-template.ts +11 -0
- package/src/mcp/postgres.ts +1 -1
- package/src/migrate/from-postgres/cli.test.ts +165 -0
- package/src/migrate/from-postgres/detect.ts +7 -0
- package/src/migrate/from-postgres/emit.ts +96 -0
- package/src/migrate/from-postgres/example.test.ts +205 -0
- package/src/migrate/from-postgres/index.ts +122 -0
- package/src/migrate/from-postgres/translate.test.ts +242 -0
- package/src/migrate/from-postgres/translate.ts +359 -0
- package/src/migrate/from-postgres/types.test.ts +116 -0
- package/src/migrate/from-postgres/types.ts +236 -0
- package/src/migrate/from-postgres/validate.e2e.test.ts +44 -0
- package/src/migrate/from-postgres/workspace.e2e.test.ts +114 -0
- package/src/migration-replay.e2e.test.ts +155 -0
- package/src/migration-replay.test.ts +173 -0
- package/src/migration-replay.ts +289 -0
- package/src/op/__snapshots__/watch-pipeline.test.ts.snap +2 -2
- package/src/op/activities/postgres-migration.ts +4 -0
- package/src/op/activity-contracts.ts +2 -0
- package/src/plugin.ts +37 -2
- package/src/postgres/apply/apply.ts +9 -1
- package/src/postgres/apply/statements.ts +74 -1
- package/src/postgres/constraint-names.ts +71 -0
- package/src/postgres/database-kinds.test.ts +384 -0
- package/src/postgres/entities.ts +266 -1
- package/src/postgres/entity-types.ts +5 -0
- package/src/postgres/import/generator.ts +42 -2
- package/src/postgres/import/live-export.ts +1 -0
- package/src/postgres/live/catalog-kinds.ts +223 -0
- package/src/postgres/live/catalog.ts +6 -1
- package/src/postgres/live/database-kinds.e2e.test.ts +164 -0
- package/src/postgres/live/describe-resources.ts +11 -2
- package/src/postgres/live/undeclarable.e2e.test.ts +13 -6
- package/src/postgres/migrate/backfill.ts +13 -1
- package/src/postgres/migrate/carry.ts +103 -8
- package/src/postgres/migrate/followups.e2e.test.ts +218 -0
- package/src/postgres/migrate/followups.test.ts +199 -0
- package/src/postgres/migrate/kinds.e2e.test.ts +5 -5
- package/src/postgres/migrate/observe.ts +53 -14
- package/src/postgres/migrate/op.ts +28 -1
- package/src/postgres/migrate/partition.e2e.test.ts +129 -0
- package/src/postgres/migrate/partition.test.ts +206 -0
- package/src/postgres/migrate/steps.ts +157 -12
- package/src/postgres/parser.ts +234 -2
- package/src/postgres/plan/deep.ts +28 -1
- package/src/postgres/plan/diff.ts +36 -1
- package/src/postgres/plan/normalize.ts +122 -1
- package/src/postgres/plan/rules.ts +10 -3
- package/src/postgres/plan/schema.ts +1 -1
- package/src/postgres/secret-options.ts +10 -0
- package/src/postgres/testing/roundtrip-schema.ts +13 -1
- package/src/postgres.ts +16 -0
- package/src/serializer.ts +13 -2
- package/src/skills/chant-sql-postgres-migration.md +3 -3
- package/src/skills/chant-sql-postgres.md +6 -1
- package/src/skills/chant-sql.md +2 -1
- package/src/sql-types-command.ts +38 -16
- package/src/sql-types.ts +11 -6
- package/src/sqlserver/fixture.test.ts +186 -0
- package/src/sqlserver/import-cli.test.ts +61 -0
- package/src/sqlserver/lexer.ts +260 -0
- package/src/sqlserver/parse.ts +865 -0
- package/src/sqlserver/translate.test.ts +396 -0
- package/src/sqlserver/translate.ts +558 -0
- package/src/sqlserver/types.test.ts +102 -0
- package/src/sqlserver/types.ts +154 -0
- package/src/sqlserver/validate.e2e.test.ts +32 -0
- package/src/sqlserver/validate.test.ts +49 -0
- package/src/sqlserver/validate.ts +76 -0
- package/src/validate.ts +5 -0
- package/src/workspace-kinds.test.ts +11 -0
- package/workspace-kinds.json +100 -2
|
@@ -21,6 +21,13 @@ import { POSTGRES_ENTITY_TYPES } from "../entity-types.js";
|
|
|
21
21
|
import { isChantManaged, readMarker, stripMarker } from "../../core/ownership.js";
|
|
22
22
|
import { identValue } from "../parser.js";
|
|
23
23
|
import { canonicalPgObject } from "../plan/normalize.js";
|
|
24
|
+
/** The entity types that belong to the database, not a schema. */
|
|
25
|
+
const UNPLACED = new Set([
|
|
26
|
+
POSTGRES_ENTITY_TYPES.eventTrigger,
|
|
27
|
+
POSTGRES_ENTITY_TYPES.foreignDataWrapper,
|
|
28
|
+
POSTGRES_ENTITY_TYPES.foreignServer,
|
|
29
|
+
POSTGRES_ENTITY_TYPES.publication,
|
|
30
|
+
]);
|
|
24
31
|
/**
|
|
25
32
|
* The schema and name a declared entity is created as; a bare name is in the
|
|
26
33
|
* default schema. A routine's parameter types and a trigger's table tell it
|
|
@@ -28,7 +35,7 @@ import { canonicalPgObject } from "../plan/normalize.js";
|
|
|
28
35
|
*/
|
|
29
36
|
export function declaredAddress(entity, defaultSchema) {
|
|
30
37
|
const name = String(entity.props.name ?? "");
|
|
31
|
-
if (entity.type === POSTGRES_ENTITY_TYPES.schema || entity.type === POSTGRES_ENTITY_TYPES.extension || entity.type === POSTGRES_ENTITY_TYPES.role || entity.type
|
|
38
|
+
if (entity.type === POSTGRES_ENTITY_TYPES.schema || entity.type === POSTGRES_ENTITY_TYPES.extension || entity.type === POSTGRES_ENTITY_TYPES.role || UNPLACED.has(entity.type))
|
|
32
39
|
return { name };
|
|
33
40
|
// A cast is named by its two types, as the catalog prints them.
|
|
34
41
|
if (entity.type === POSTGRES_ENTITY_TYPES.cast)
|
|
@@ -37,6 +44,7 @@ export function declaredAddress(entity, defaultSchema) {
|
|
|
37
44
|
if (entity.type === POSTGRES_ENTITY_TYPES.function ||
|
|
38
45
|
entity.type === POSTGRES_ENTITY_TYPES.procedure ||
|
|
39
46
|
entity.type === POSTGRES_ENTITY_TYPES.aggregate ||
|
|
47
|
+
entity.type === POSTGRES_ENTITY_TYPES.operator ||
|
|
40
48
|
entity.type === POSTGRES_ENTITY_TYPES.trigger ||
|
|
41
49
|
entity.type === POSTGRES_ENTITY_TYPES.policy) {
|
|
42
50
|
const signature = canonicalPgObject(entity.type, entity.props, defaultSchema).signature;
|
|
@@ -66,7 +74,7 @@ export function scopeFor(target, entities) {
|
|
|
66
74
|
return undefined;
|
|
67
75
|
const out = new Set([target.defaultSchema]);
|
|
68
76
|
// The schema alone: the rest of an address (a routine's parameter types) needs props a caller may not have.
|
|
69
|
-
const unplaced = new Set([POSTGRES_ENTITY_TYPES.extension, POSTGRES_ENTITY_TYPES.role, POSTGRES_ENTITY_TYPES.cast,
|
|
77
|
+
const unplaced = new Set([POSTGRES_ENTITY_TYPES.extension, POSTGRES_ENTITY_TYPES.role, POSTGRES_ENTITY_TYPES.cast, ...UNPLACED]);
|
|
70
78
|
for (const e of entities) {
|
|
71
79
|
if (e.type === POSTGRES_ENTITY_TYPES.schema)
|
|
72
80
|
out.add(String(e.props.name ?? ""));
|
|
@@ -87,6 +87,8 @@ export interface VerifyResult {
|
|
|
87
87
|
mismatched: number;
|
|
88
88
|
/** Rows whose new column is NULL. */
|
|
89
89
|
nulls: number;
|
|
90
|
+
/** A rename with a type change: rows whose old column differs from `reverse` over the new one. */
|
|
91
|
+
unreversed?: number;
|
|
90
92
|
/** The sum of a 64-bit hash of every new value, and of every value the expression gives. */
|
|
91
93
|
checksum: string;
|
|
92
94
|
expected: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backfill.d.ts","sourceRoot":"","sources":["../../../src/postgres/migrate/backfill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAKH,OAAO,EAA0C,KAAK,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAC9F,OAAO,EAAwC,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAmD,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAE7F,OAAO,EAAiD,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAEtF,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACrC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+DAA+D;AAC/D,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,OAAO,MAAM,KAAG,MAAmC,CAAC;AAE7F,8IAA8I;AAC9I,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,oBAAoB,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,QAAQ,CAAC,GAAG,MAAM,CASrG;AAED,mGAAmG;AACnG,eAAO,MAAM,cAAc,YAAY,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,yFAAyF;IACzF,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,+GAA+G;IAC/G,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,4EAA4E;IAC5E,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,2CAA2C;IAC3C,eAAe,CAAC,EAAE,OAAO,eAAe,CAAC;CAC1C;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CA2DlG;AAID,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACrC,8GAA8G;IAC9G,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,4FAA4F;IAC5F,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,uDAAuD;AACvD,qBAAa,0BAA2B,SAAQ,KAAK;IAEjD,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,YAAY,CAAC;gBADpD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,YAAY,CAAC,EAC7D,MAAM,EAAE,MAAM;CAKjB;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"backfill.d.ts","sourceRoot":"","sources":["../../../src/postgres/migrate/backfill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAKH,OAAO,EAA0C,KAAK,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAC9F,OAAO,EAAwC,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAmD,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAE7F,OAAO,EAAiD,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAEtF,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACrC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+DAA+D;AAC/D,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,OAAO,MAAM,KAAG,MAAmC,CAAC;AAE7F,8IAA8I;AAC9I,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,oBAAoB,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,QAAQ,CAAC,GAAG,MAAM,CASrG;AAED,mGAAmG;AACnG,eAAO,MAAM,cAAc,YAAY,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,yFAAyF;IACzF,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,+GAA+G;IAC/G,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,4EAA4E;IAC5E,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,2CAA2C;IAC3C,eAAe,CAAC,EAAE,OAAO,eAAe,CAAC;CAC1C;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CA2DlG;AAID,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACrC,8GAA8G;IAC9G,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,kGAAkG;IAClG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4FAA4F;IAC5F,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,uDAAuD;AACvD,qBAAa,0BAA2B,SAAQ,KAAK;IAEjD,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,YAAY,CAAC;gBADpD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,YAAY,CAAC,EAC7D,MAAM,EAAE,MAAM;CAKjB;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAoD9E"}
|
|
@@ -142,6 +142,7 @@ export async function verifyMigration(run) {
|
|
|
142
142
|
const nw = col(n.newColumn);
|
|
143
143
|
const [row] = await inTransaction(run, (exec) => exec(`SELECT count(*)::text AS rows, count(*) FILTER (WHERE ${nw} IS DISTINCT FROM (${o.expression}))::text AS mismatched,
|
|
144
144
|
count(*) FILTER (WHERE ${nw} IS NULL)::text AS nulls,
|
|
145
|
+
${o.reverse !== undefined ? `count(*) FILTER (WHERE (${o.reverse}) IS DISTINCT FROM ${col(n.source)})::text` : "'0'"} AS unreversed,
|
|
145
146
|
COALESCE(sum(pg_catalog.hashtextextended(${nw}::text, 0)), 0)::text AS checksum,
|
|
146
147
|
COALESCE(sum(pg_catalog.hashtextextended((${o.expression})::text, 0)), 0)::text AS expected
|
|
147
148
|
FROM ${n.qualifiedTable}`), { scan: true });
|
|
@@ -149,6 +150,10 @@ export async function verifyMigration(run) {
|
|
|
149
150
|
if (r.mismatched > 0 || r.checksum !== r.expected) {
|
|
150
151
|
throw new MigrationVerificationError(n.key, { state: o.state, ...r }, `${r.mismatched} of ${r.rows} row(s) have ${n.newColumn} different from ${o.expression} (checksums ${r.checksum} and ${r.expected})`);
|
|
151
152
|
}
|
|
153
|
+
const unreversed = Number(row?.unreversed ?? 0);
|
|
154
|
+
if (o.reverse !== undefined && unreversed > 0) {
|
|
155
|
+
throw new MigrationVerificationError(n.key, { state: o.state, ...r, unreversed }, `${unreversed} of ${r.rows} row(s) have ${n.source} different from ${o.reverse}, which must give the old value back from the new one (it would write ${n.source} wrongly for a writer of ${n.column})`);
|
|
156
|
+
}
|
|
152
157
|
if (requiresNotNull(o.column, o.carried) && r.nulls > 0) {
|
|
153
158
|
throw new MigrationVerificationError(n.key, { state: o.state, ...r }, `${r.nulls} of ${r.rows} row(s) have ${n.newColumn} NULL, and ${n.column} is declared NOT NULL or is in the primary key`);
|
|
154
159
|
}
|
|
@@ -159,12 +164,13 @@ export async function verifyMigration(run) {
|
|
|
159
164
|
const carried = o.carried.length > 0 || o.views.length > 0
|
|
160
165
|
? `; ${o.carried.map((c) => `${c.kind} ${c.name}${c.target !== c.name ? ` (as ${c.target})` : ""}`).join(", ") || "no index or constraint"} carried over${o.views.length > 0 ? `, view(s) ${o.views.map((v) => v.name).join(", ")} made again at the switch` : ""}`
|
|
161
166
|
: "";
|
|
162
|
-
const summary = `${n.key}: ${r.rows} row(s), ${n.newColumn} equal to ${o.expression} in every one (checksum ${r.checksum})${carried}`;
|
|
167
|
+
const summary = `${n.key}: ${r.rows} row(s), ${n.newColumn} equal to ${o.expression} in every one (checksum ${r.checksum})${o.reverse !== undefined ? `, ${n.source} equal to ${o.reverse} in every one` : ""}${carried}`;
|
|
163
168
|
run.log(`-- ${summary}`);
|
|
164
169
|
return {
|
|
165
170
|
state: o.state,
|
|
166
171
|
planDigest: computePlanDigest("postgres-migration", { plan: migrationPlanSubject(o), table: o.oid, column: o.newColumn.attnum, verified: { mismatched: 0 } }),
|
|
167
172
|
...r,
|
|
173
|
+
...(o.reverse !== undefined ? { unreversed } : {}),
|
|
168
174
|
summary,
|
|
169
175
|
};
|
|
170
176
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* | On the old column | Before the switch | In the switch's transaction |
|
|
11
11
|
* |---|---|---|
|
|
12
12
|
* | an index | `CREATE INDEX CONCURRENTLY` on the new column | the old one dropped (a type change) or kept as `<name>__chant_old` (a rename), the new one renamed to the name |
|
|
13
|
+
* | an index on a partitioned table | `CREATE INDEX ... ON ONLY` the table, `CONCURRENTLY` on each partition, `ALTER INDEX ... ATTACH PARTITION` | as an index; the partitions' indexes go with the old one |
|
|
13
14
|
* | a primary key or unique constraint | its unique index built `CONCURRENTLY` | the old constraint dropped (or a rename's unique one kept as `__chant_old`), `ADD CONSTRAINT ... USING INDEX` |
|
|
14
15
|
* | a check or foreign key, this table's or another's that references the column | added `NOT VALID`, then `VALIDATE` | the old one dropped, the new one renamed to the name |
|
|
15
16
|
* | a view (and the views that read it) | nothing | dropped, then created again from its declaration once the columns are swapped, with its grants and owner |
|
|
@@ -33,7 +34,8 @@
|
|
|
33
34
|
* key or index the build declares on the new column takes the declared name.
|
|
34
35
|
*
|
|
35
36
|
* Refused, each named with what to do: exclusion constraints and constraint
|
|
36
|
-
* triggers (no `USING INDEX` form),
|
|
37
|
+
* triggers (no `USING INDEX` form), a key or foreign key on a partitioned table,
|
|
38
|
+
* a partitioned index over a foreign-table partition, materialized views (made again only by
|
|
37
39
|
* a full scan in the switch), rules, triggers, policies and statistics on the
|
|
38
40
|
* column, a generated column computed from it, an INVALID index on it, a view
|
|
39
41
|
* the build does not declare, a view something other than a view depends on.
|
|
@@ -77,6 +79,12 @@ export interface CarriedObject {
|
|
|
77
79
|
indexComment?: string;
|
|
78
80
|
replicaIdentity?: boolean;
|
|
79
81
|
clustered?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* An index on a partitioned table (#3333): `definition` is the `CREATE INDEX ... ON ONLY` that makes the
|
|
84
|
+
* partitioned index without building anything. Each partition's index is built `CONCURRENTLY` on its own and
|
|
85
|
+
* attached (`partitionIndexStatement`, `carryPartitionedIndex` in `./steps.ts`).
|
|
86
|
+
*/
|
|
87
|
+
partitioned?: boolean;
|
|
80
88
|
}
|
|
81
89
|
/** A view on the old column (or on such a view), made again at the switch from its declaration. */
|
|
82
90
|
export interface CarriedView {
|
|
@@ -130,6 +138,38 @@ export declare function replaceInForeignKey(def: string, from: string, to: strin
|
|
|
130
138
|
* the `CONCURRENTLY` build of `working` on the new column.
|
|
131
139
|
*/
|
|
132
140
|
export declare function carriedIndexStatement(def: string, working: string, from: string, to: string): string;
|
|
141
|
+
/**
|
|
142
|
+
* A partitioned index (`pg_get_indexdef` prints it `ON ONLY`) as the
|
|
143
|
+
* `CREATE INDEX ... ON ONLY` of `working` on the new column: it builds nothing
|
|
144
|
+
* and stays INVALID until every partition's index is attached.
|
|
145
|
+
*/
|
|
146
|
+
export declare function carriedPartitionedIndexStatement(def: string, working: string, from: string, to: string): string;
|
|
147
|
+
/** One table of a partition tree. */
|
|
148
|
+
export interface PartitionNode {
|
|
149
|
+
oid: string;
|
|
150
|
+
schema: string;
|
|
151
|
+
name: string;
|
|
152
|
+
/** Quoted and qualified. */
|
|
153
|
+
ident: string;
|
|
154
|
+
/** The partitioned table (or partition) it is a partition of; absent for the root. */
|
|
155
|
+
parent?: string;
|
|
156
|
+
/** Not partitioned further: the tables that hold rows. */
|
|
157
|
+
leaf: boolean;
|
|
158
|
+
/** `r` (ordinary), `p` (partitioned) or `f` (foreign). */
|
|
159
|
+
kind: string;
|
|
160
|
+
level: number;
|
|
161
|
+
}
|
|
162
|
+
/** The partition tree under a partitioned table, the table itself first (level 0). */
|
|
163
|
+
export declare function partitionTree(client: Pick<PostgresClient, "query">, tableOid: string): Promise<PartitionNode[]>;
|
|
164
|
+
/** The name of the index a partitioned index's working copy has on one partition. */
|
|
165
|
+
export declare const partitionIndexName: (partition: Pick<PartitionNode, "name">, working: string) => string;
|
|
166
|
+
/**
|
|
167
|
+
* The statement that makes a partitioned index's working copy on one
|
|
168
|
+
* partition. A partition that is partitioned further gets `ON ONLY` (it is
|
|
169
|
+
* valid once its own partitions are attached); one that holds rows gets the
|
|
170
|
+
* `CONCURRENTLY` build, so writes go on.
|
|
171
|
+
*/
|
|
172
|
+
export declare function partitionIndexStatement(c: Pick<CarriedObject, "definition">, node: Pick<PartitionNode, "ident" | "leaf">, indexName: string): string;
|
|
133
173
|
/**
|
|
134
174
|
* The name Postgres gives an object it names after its columns
|
|
135
175
|
* (`users_email_key`, `orders_user_id_fkey`, `users_email_idx`), when `name`
|
|
@@ -149,7 +189,11 @@ interface DiscoverInput {
|
|
|
149
189
|
defaultSchema: string;
|
|
150
190
|
/** The table is partitioned: its indexes cannot be built CONCURRENTLY, nor its keys attached USING INDEX. */
|
|
151
191
|
partitioned?: boolean;
|
|
192
|
+
/** A rename keeps the column's sequence on the old column until the contract (`defaultAtContract`), instead of being refused. */
|
|
193
|
+
keepSequence?: boolean;
|
|
152
194
|
}
|
|
195
|
+
/** The sequence that belongs to a column (an identity's, or a `serial`'s), if it has one. */
|
|
196
|
+
export declare function columnSequence(client: PostgresClient, tableOid: string, attnum: number): Promise<ColumnSequence | undefined>;
|
|
153
197
|
/** What uses the column the values come from, sorted into what the Op carries over and what it refuses. */
|
|
154
198
|
export declare function discoverDependents(input: DiscoverInput): Promise<Dependents>;
|
|
155
199
|
/** `ALTER TABLE ... ADD CONSTRAINT <working> <body> NOT VALID`: a check or foreign key on the new column. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"carry.d.ts","sourceRoot":"","sources":["../../../src/postgres/migrate/carry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"carry.d.ts","sourceRoot":"","sources":["../../../src/postgres/migrate/carry.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* | On the old column | Before the switch | In the switch's transaction |
|
|
11
11
|
* |---|---|---|
|
|
12
12
|
* | an index | `CREATE INDEX CONCURRENTLY` on the new column | the old one dropped (a type change) or kept as `<name>__chant_old` (a rename), the new one renamed to the name |
|
|
13
|
+
* | an index on a partitioned table | `CREATE INDEX ... ON ONLY` the table, `CONCURRENTLY` on each partition, `ALTER INDEX ... ATTACH PARTITION` | as an index; the partitions' indexes go with the old one |
|
|
13
14
|
* | a primary key or unique constraint | its unique index built `CONCURRENTLY` | the old constraint dropped (or a rename's unique one kept as `__chant_old`), `ADD CONSTRAINT ... USING INDEX` |
|
|
14
15
|
* | a check or foreign key, this table's or another's that references the column | added `NOT VALID`, then `VALIDATE` | the old one dropped, the new one renamed to the name |
|
|
15
16
|
* | a view (and the views that read it) | nothing | dropped, then created again from its declaration once the columns are swapped, with its grants and owner |
|
|
@@ -33,7 +34,8 @@
|
|
|
33
34
|
* key or index the build declares on the new column takes the declared name.
|
|
34
35
|
*
|
|
35
36
|
* Refused, each named with what to do: exclusion constraints and constraint
|
|
36
|
-
* triggers (no `USING INDEX` form),
|
|
37
|
+
* triggers (no `USING INDEX` form), a key or foreign key on a partitioned table,
|
|
38
|
+
* a partitioned index over a foreign-table partition, materialized views (made again only by
|
|
37
39
|
* a full scan in the switch), rules, triggers, policies and statistics on the
|
|
38
40
|
* column, a generated column computed from it, an INVALID index on it, a view
|
|
39
41
|
* the build does not declare, a view something other than a view depends on.
|
|
@@ -120,6 +122,53 @@ export function carriedIndexStatement(def, working, from, to) {
|
|
|
120
122
|
throw new Error(`unexpected index definition: ${def}`);
|
|
121
123
|
return `CREATE ${m[1] ?? ""}INDEX CONCURRENTLY ${quoteIdent(working)} ON ${replaceColumn(m[2], from, to)}`;
|
|
122
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* A partitioned index (`pg_get_indexdef` prints it `ON ONLY`) as the
|
|
127
|
+
* `CREATE INDEX ... ON ONLY` of `working` on the new column: it builds nothing
|
|
128
|
+
* and stays INVALID until every partition's index is attached.
|
|
129
|
+
*/
|
|
130
|
+
export function carriedPartitionedIndexStatement(def, working, from, to) {
|
|
131
|
+
const m = /^CREATE (UNIQUE )?INDEX (?:"(?:[^"]|"")+"|\S+) ON (?:ONLY )?(.*)$/s.exec(def);
|
|
132
|
+
if (!m)
|
|
133
|
+
throw new Error(`unexpected index definition: ${def}`);
|
|
134
|
+
return `CREATE ${m[1] ?? ""}INDEX ${quoteIdent(working)} ON ONLY ${replaceColumn(m[2], from, to)}`;
|
|
135
|
+
}
|
|
136
|
+
/** The partition tree under a partitioned table, the table itself first (level 0). */
|
|
137
|
+
export async function partitionTree(client, tableOid) {
|
|
138
|
+
const rows = await client.query(`SELECT t.relid::oid::text AS oid, n.nspname AS schema, c.relname AS name, t.parentrelid::oid::text AS parent, t.isleaf AS leaf, c.relkind::text AS kind, t.level
|
|
139
|
+
FROM pg_catalog.pg_partition_tree($1::oid::pg_catalog.regclass) t JOIN pg_catalog.pg_class c ON c.oid = t.relid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
140
|
+
ORDER BY t.level, n.nspname, c.relname`, [tableOid]);
|
|
141
|
+
return rows.map((r) => ({
|
|
142
|
+
oid: String(r.oid),
|
|
143
|
+
schema: r.schema,
|
|
144
|
+
name: r.name,
|
|
145
|
+
ident: `${quoteIdent(r.schema)}.${quoteIdent(r.name)}`,
|
|
146
|
+
...(r.parent !== null ? { parent: String(r.parent) } : {}),
|
|
147
|
+
leaf: r.leaf === true,
|
|
148
|
+
kind: r.kind,
|
|
149
|
+
level: Number(r.level),
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
/** The name of the index a partitioned index's working copy has on one partition. */
|
|
153
|
+
export const partitionIndexName = (partition, working) => pgName(`${partition.name}_${working}`);
|
|
154
|
+
/**
|
|
155
|
+
* The statement that makes a partitioned index's working copy on one
|
|
156
|
+
* partition. A partition that is partitioned further gets `ON ONLY` (it is
|
|
157
|
+
* valid once its own partitions are attached); one that holds rows gets the
|
|
158
|
+
* `CONCURRENTLY` build, so writes go on.
|
|
159
|
+
*/
|
|
160
|
+
export function partitionIndexStatement(c, node, indexName) {
|
|
161
|
+
const m = /^CREATE (UNIQUE )?INDEX (?:"(?:[^"]|"")+"|\S+) ON ONLY (.*)$/s.exec(c.definition);
|
|
162
|
+
if (!m)
|
|
163
|
+
throw new Error(`unexpected partitioned index definition: ${c.definition}`);
|
|
164
|
+
const using = m[2].indexOf(" USING ");
|
|
165
|
+
if (using < 0)
|
|
166
|
+
throw new Error(`unexpected partitioned index definition: ${c.definition}`);
|
|
167
|
+
const tail = m[2].slice(using);
|
|
168
|
+
return node.leaf
|
|
169
|
+
? `CREATE ${m[1] ?? ""}INDEX CONCURRENTLY ${quoteIdent(indexName)} ON ${node.ident}${tail}`
|
|
170
|
+
: `CREATE ${m[1] ?? ""}INDEX ${quoteIdent(indexName)} ON ONLY ${node.ident}${tail}`;
|
|
171
|
+
}
|
|
123
172
|
/**
|
|
124
173
|
* The name Postgres gives an object it names after its columns
|
|
125
174
|
* (`users_email_key`, `orders_user_id_fkey`, `users_email_idx`), when `name`
|
|
@@ -134,6 +183,15 @@ export function renamedDefault(name, table, oldCols, newCols, suffix) {
|
|
|
134
183
|
return Buffer.byteLength(next, "utf8") <= 63 && next !== name ? next : undefined;
|
|
135
184
|
}
|
|
136
185
|
const sameColumns = (a, b) => a.length === b.length && a.every((c, i) => c === b[i]);
|
|
186
|
+
/** The sequence that belongs to a column (an identity's, or a `serial`'s), if it has one. */
|
|
187
|
+
export async function columnSequence(client, tableOid, attnum) {
|
|
188
|
+
const [row] = await client.query(`SELECT n.nspname AS schema, c.relname AS name, d.deptype::text AS deptype
|
|
189
|
+
FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_class c ON c.oid = d.objid AND d.classid = 'pg_catalog.pg_class'::pg_catalog.regclass JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
190
|
+
WHERE d.refclassid = 'pg_catalog.pg_class'::pg_catalog.regclass AND d.refobjid = $1::oid AND d.refobjsubid = $2 AND d.deptype IN ('a', 'i') AND c.relkind = 'S'`, [tableOid, attnum]);
|
|
191
|
+
if (!row)
|
|
192
|
+
return undefined;
|
|
193
|
+
return { kind: row.deptype === "i" ? "identity" : "serial", schema: row.schema, name: row.name, ident: `${quoteIdent(row.schema)}.${quoteIdent(row.name)}` };
|
|
194
|
+
}
|
|
137
195
|
/** What uses the column the values come from, sorted into what the Op carries over and what it refuses. */
|
|
138
196
|
export async function discoverDependents(input) {
|
|
139
197
|
const { client, names: n, oid, attnum } = input;
|
|
@@ -251,10 +309,6 @@ export async function discoverDependents(input) {
|
|
|
251
309
|
if (kind === "i" || kind === "I") {
|
|
252
310
|
if (keyIndexes.has(String(r.oid)))
|
|
253
311
|
continue;
|
|
254
|
-
if (kind === "I") {
|
|
255
|
-
refused.push(`index ${r.schema}.${name} is a partitioned index, which cannot be built CONCURRENTLY; drop it, migrate, then declare it again (chant #3333)`);
|
|
256
|
-
continue;
|
|
257
|
-
}
|
|
258
312
|
if (r.valid !== true) {
|
|
259
313
|
refused.push(`index ${r.schema}.${name} is INVALID (a failed CONCURRENTLY build); drop it, or REINDEX it, first`);
|
|
260
314
|
continue;
|
|
@@ -277,6 +331,14 @@ export async function discoverDependents(input) {
|
|
|
277
331
|
});
|
|
278
332
|
target = declaredIndex?.canonical.name ?? (r.has_exprs === true ? undefined : renamedDefault(name, table, oldCols, cols, "idx")) ?? name;
|
|
279
333
|
}
|
|
334
|
+
if (kind === "I") {
|
|
335
|
+
// A partition the index cannot be built on (a foreign table) stops the carry before anything is made.
|
|
336
|
+
const foreign = (await partitionTree(client, oid)).filter((p) => p.kind === "f");
|
|
337
|
+
if (foreign.length > 0) {
|
|
338
|
+
refused.push(`partitioned index ${r.schema}.${name}: ${foreign.map((p) => `${p.schema}.${p.name}`).join(", ")} is a foreign table, which holds no index to attach; drop the index, migrate, then declare it again`);
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
280
342
|
carried.push({
|
|
281
343
|
kind: "index",
|
|
282
344
|
name,
|
|
@@ -286,7 +348,8 @@ export async function discoverDependents(input) {
|
|
|
286
348
|
schema: String(r.schema),
|
|
287
349
|
working,
|
|
288
350
|
target,
|
|
289
|
-
definition: carriedIndexStatement(String(r.def), working, from, to),
|
|
351
|
+
definition: kind === "I" ? carriedPartitionedIndexStatement(String(r.def), working, from, to) : carriedIndexStatement(String(r.def), working, from, to),
|
|
352
|
+
...(kind === "I" ? { partitioned: true } : {}),
|
|
290
353
|
validated: true,
|
|
291
354
|
...(r.comment !== null ? { comment: String(r.comment) } : {}),
|
|
292
355
|
...(r.replident === true ? { replicaIdentity: true } : {}),
|
|
@@ -296,8 +359,9 @@ export async function discoverDependents(input) {
|
|
|
296
359
|
else if (kind === "S") {
|
|
297
360
|
const dep = deps.find((d) => d.kind === "class" && d.objid === String(r.oid));
|
|
298
361
|
const seq = { kind: dep?.deptype === "i" ? "identity" : "serial", schema: String(r.schema), name, ident: `${quoteIdent(String(r.schema))}.${quoteIdent(name)}` };
|
|
299
|
-
if (rename) {
|
|
300
|
-
refused.push(`sequence ${r.schema}.${name} gives the column its values (${seq.kind === "identity" ? "an identity column" : "a serial column's default"}); during a rename a writer that names the new column would
|
|
362
|
+
if (rename && !input.keepSequence) {
|
|
363
|
+
refused.push(`sequence ${r.schema}.${name} gives the column its values (${seq.kind === "identity" ? "an identity column" : "a serial column's default"}); during a rename a writer that names the new column would get the old one's next value, and the trigger would take it over the writer's, ` +
|
|
364
|
+
`because it cannot tell a defaulted value from one the writer gave. Set defaultAtContract: true to leave the new column without the default until the contract (see the Op's reference), or drop the default first`);
|
|
301
365
|
}
|
|
302
366
|
else
|
|
303
367
|
sequence = seq;
|
|
@@ -24,12 +24,13 @@
|
|
|
24
24
|
* - `done`: the server holds the declared column and nothing of the
|
|
25
25
|
* migration is left.
|
|
26
26
|
*
|
|
27
|
+
* A partitioned table's indexes are carried over per partition (`./steps.ts`).
|
|
27
28
|
* Anything else is refused with a {@link MigrationRefusal}, naming what to
|
|
28
29
|
* do: a table that is not there, a partition (run it on the partitioned
|
|
29
30
|
* table) or an inheritance tree; no primary key to batch by; a column in the
|
|
30
31
|
* partition key; a generated column; a column change the Op does not make
|
|
31
|
-
* (a rename and a type change
|
|
32
|
-
* or a sequence); something that uses the column and is
|
|
32
|
+
* (a rename and a type change without `reverse`, a rename of a column with a
|
|
33
|
+
* default or a sequence without `defaultAtContract`); something that uses the column and is
|
|
33
34
|
* not carried over to the new one (`./carry.ts`: indexes, key, check and
|
|
34
35
|
* foreign key constraints and declared views are); a publication that sends
|
|
35
36
|
* it; a working object chant did not make.
|
|
@@ -43,7 +44,7 @@ import type { DeclaredPgObject } from "../apply/statements.js";
|
|
|
43
44
|
import { MIGRATION_TRAILER_KEY, type MigrationNames } from "./names.js";
|
|
44
45
|
import { type PublicationHit } from "./replication.js";
|
|
45
46
|
import { type KeyColumn } from "./batches.js";
|
|
46
|
-
import { type CarriedObject, type CarriedState, type CarriedView, type ColumnSequence } from "./carry.js";
|
|
47
|
+
import { type CarriedObject, type CarriedState, type CarriedView, type ColumnSequence, type Dependents } from "./carry.js";
|
|
47
48
|
/** A refusal: the migration cannot start, or cannot go on, for a reason a person has to act on. */
|
|
48
49
|
export declare class MigrationRefusal extends Error {
|
|
49
50
|
constructor(message: string);
|
|
@@ -87,7 +88,7 @@ export interface MigrationObservation {
|
|
|
87
88
|
carriedStates: Map<string, CarriedState>;
|
|
88
89
|
/** The views that read the old column, made again at the switch. */
|
|
89
90
|
views: CarriedView[];
|
|
90
|
-
/** The sequence that gives the old column its values (identity or serial)
|
|
91
|
+
/** The sequence that gives the old column its values (identity or serial): moved to the new column at the switch for a type change, at the contract for a rename. */
|
|
91
92
|
sequence?: ColumnSequence;
|
|
92
93
|
/** The table is partitioned: every step runs on it, and its partitions follow. */
|
|
93
94
|
partitioned: boolean;
|
|
@@ -105,6 +106,10 @@ export interface MigrationObservation {
|
|
|
105
106
|
changes: PgChange[];
|
|
106
107
|
/** The expression the new column's value is computed with, over the old row's columns. */
|
|
107
108
|
expression: string;
|
|
109
|
+
/** A rename with a type change: the expression over the new row's columns that gives the old column's value. */
|
|
110
|
+
reverse?: string;
|
|
111
|
+
/** A rename keeps its default, serial or identity on the old column until the contract (`defaultAtContract`). */
|
|
112
|
+
defaultAtContract?: boolean;
|
|
108
113
|
publications: PublicationHit[];
|
|
109
114
|
major: number;
|
|
110
115
|
}
|
|
@@ -118,6 +123,10 @@ export interface ObserveInput {
|
|
|
118
123
|
objects?: readonly DeclaredPgObject[];
|
|
119
124
|
/** The type change's expression, over the old row's columns. Default: `CAST(<column> AS <declared type>)`. */
|
|
120
125
|
using?: string;
|
|
126
|
+
/** A rename with a type change: the expression over the new row's columns that gives the old column's value. */
|
|
127
|
+
reverse?: string;
|
|
128
|
+
/** A rename of a column with a default, serial or identity: the declared default lands on the new column at the contract, not the switch. */
|
|
129
|
+
defaultAtContract?: boolean;
|
|
121
130
|
/** The major the build targets; the server's own wins. */
|
|
122
131
|
major?: number;
|
|
123
132
|
}
|
|
@@ -125,8 +134,23 @@ export interface ObserveInput {
|
|
|
125
134
|
export declare function declaredTable(declared: readonly DeclaredPgObject[], key: string): DeclaredPgObject;
|
|
126
135
|
/** The server's major, from `server_version_num`. */
|
|
127
136
|
export declare function serverMajor(client: PostgresClient): Promise<number>;
|
|
137
|
+
export interface RelationRow {
|
|
138
|
+
oid: string;
|
|
139
|
+
kind: string;
|
|
140
|
+
partition: boolean;
|
|
141
|
+
parents: string | null;
|
|
142
|
+
children: string | null;
|
|
143
|
+
partkey: string | null;
|
|
144
|
+
partattrs: number[] | null;
|
|
145
|
+
}
|
|
128
146
|
/** Observe the migration of the declared table's column on the server. */
|
|
129
147
|
export declare function observeMigration(input: ObserveInput): Promise<MigrationObservation>;
|
|
148
|
+
/** The checks that hold only while there is something to migrate. Returns the batch key and what the Op carries over. */
|
|
149
|
+
export declare function refuseUnsupported(input: ObserveInput, names: MigrationNames, rel: RelationRow, source: ServerColumn, column: ColumnDef, changes: readonly PgChange[], rename: boolean, typeChange: PgChange | undefined): Promise<{
|
|
150
|
+
batchKey: string;
|
|
151
|
+
keyColumns: KeyColumn[];
|
|
152
|
+
dependents: Pick<Dependents, "carried" | "views" | "sequence">;
|
|
153
|
+
}>;
|
|
130
154
|
/**
|
|
131
155
|
* What the migration will do, independent of how far it has got: the
|
|
132
156
|
* change, the column on both sides, the expression, the batch key. The
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../../src/postgres/migrate/observe.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../../src/postgres/migrate/observe.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,12 +24,13 @@
|
|
|
24
24
|
* - `done`: the server holds the declared column and nothing of the
|
|
25
25
|
* migration is left.
|
|
26
26
|
*
|
|
27
|
+
* A partitioned table's indexes are carried over per partition (`./steps.ts`).
|
|
27
28
|
* Anything else is refused with a {@link MigrationRefusal}, naming what to
|
|
28
29
|
* do: a table that is not there, a partition (run it on the partitioned
|
|
29
30
|
* table) or an inheritance tree; no primary key to batch by; a column in the
|
|
30
31
|
* partition key; a generated column; a column change the Op does not make
|
|
31
|
-
* (a rename and a type change
|
|
32
|
-
* or a sequence); something that uses the column and is
|
|
32
|
+
* (a rename and a type change without `reverse`, a rename of a column with a
|
|
33
|
+
* default or a sequence without `defaultAtContract`); something that uses the column and is
|
|
33
34
|
* not carried over to the new one (`./carry.ts`: indexes, key, check and
|
|
34
35
|
* foreign key constraints and declared views are); a publication that sends
|
|
35
36
|
* it; a working object chant did not make.
|
|
@@ -43,7 +44,7 @@ import { POSTGRES_ENTITY_TYPES } from "../entity-types.js";
|
|
|
43
44
|
import { col, migrationNames, MIGRATION_TRAILER_KEY, pgName } from "./names.js";
|
|
44
45
|
import { publicationsOf } from "./replication.js";
|
|
45
46
|
import { keyText } from "./batches.js";
|
|
46
|
-
import { carriedStates, carriedSubject, discoverDependents, replaceColumn, storedType } from "./carry.js";
|
|
47
|
+
import { carriedStates, carriedSubject, columnSequence, discoverDependents, replaceColumn, storedType } from "./carry.js";
|
|
47
48
|
/** A refusal: the migration cannot start, or cannot go on, for a reason a person has to act on. */
|
|
48
49
|
export class MigrationRefusal extends Error {
|
|
49
50
|
constructor(message) {
|
|
@@ -241,7 +242,8 @@ export async function observeMigration(input) {
|
|
|
241
242
|
}, (what) => {
|
|
242
243
|
throw new MigrationRefusal(`${where}: ${what} exists and is not this migration's (its comment carries no migration=${names.key} role=carry marker for this project). The migration uses that name, so it stops rather than touch it; rename or drop it by hand.`);
|
|
243
244
|
});
|
|
244
|
-
|
|
245
|
+
const retyped = change === "rename" && input.reverse !== undefined;
|
|
246
|
+
if (change === "type" || retyped) {
|
|
245
247
|
expression = input.using ?? `CAST(${col(sourceName)} AS ${storedType(column.type)})`;
|
|
246
248
|
if (expression.includes("$chant$"))
|
|
247
249
|
throw new MigrationRefusal(`${where}: the using expression may not contain $chant$, which quotes the dual-write function's body`);
|
|
@@ -251,7 +253,7 @@ export async function observeMigration(input) {
|
|
|
251
253
|
}
|
|
252
254
|
// The declared type as the classifier compared it: the server's spelling (character varying(10), not varchar(10)).
|
|
253
255
|
const serial = storedType(column.type) !== column.type;
|
|
254
|
-
const expectedType = change === "type" ? (serial ? storedType(column.type) : String(typeChange?.after ?? column.type)) : source.type;
|
|
256
|
+
const expectedType = change === "type" || retyped ? (serial ? storedType(column.type) : String(typeChange?.after ?? column.type)) : source.type;
|
|
255
257
|
if (newColumn && newColumn.type !== expectedType) {
|
|
256
258
|
throw new MigrationRefusal(`${where}: ${newColumn.name} was made as ${newColumn.type}, from another declaration of ${input.column} (now ${column.type}). The run fails so onFailure drops it, and the next run starts again from the current declaration.`);
|
|
257
259
|
}
|
|
@@ -264,6 +266,12 @@ export async function observeMigration(input) {
|
|
|
264
266
|
`A migration of the publisher and the subscriber together is chant #3332.`);
|
|
265
267
|
}
|
|
266
268
|
}
|
|
269
|
+
// After a rename's switch the old column still holds the default or the identity the contract moves, and its sequence is read for it.
|
|
270
|
+
if (state === "switched" && old && (old.identity || old.default?.includes("nextval("))) {
|
|
271
|
+
const seq = await columnSequence(client, rel.oid, old.attnum);
|
|
272
|
+
if (seq)
|
|
273
|
+
dependents = { ...dependents, sequence: seq };
|
|
274
|
+
}
|
|
267
275
|
return {
|
|
268
276
|
state,
|
|
269
277
|
names,
|
|
@@ -286,23 +294,41 @@ export async function observeMigration(input) {
|
|
|
286
294
|
...(check ? { check } : {}),
|
|
287
295
|
changes,
|
|
288
296
|
expression,
|
|
297
|
+
...(input.reverse !== undefined && state === "migrate" ? { reverse: input.reverse } : {}),
|
|
298
|
+
...(input.defaultAtContract && state === "migrate" ? { defaultAtContract: true } : {}),
|
|
289
299
|
publications,
|
|
290
300
|
major,
|
|
291
301
|
};
|
|
292
302
|
}
|
|
293
303
|
/** The checks that hold only while there is something to migrate. Returns the batch key and what the Op carries over. */
|
|
294
|
-
async function refuseUnsupported(input, names, rel, source, column, changes, rename, typeChange) {
|
|
304
|
+
export async function refuseUnsupported(input, names, rel, source, column, changes, rename, typeChange) {
|
|
295
305
|
const where = `${names.schema}.${names.table}`;
|
|
296
306
|
const oid = rel.oid;
|
|
297
|
-
if (rename && typeChange) {
|
|
307
|
+
if (rename && typeChange && input.reverse === undefined) {
|
|
298
308
|
throw new MigrationRefusal(`${where}: ${source.name} is renamed to ${names.column} and its type changes (${typeChange.before} -> ${typeChange.after}) in one declaration. ` +
|
|
299
|
-
`
|
|
300
|
-
`(
|
|
309
|
+
`Both names stay written until the contract, so a writer of the new name needs its value converted back to the old type: give that expression as reverse ` +
|
|
310
|
+
`(over the row's columns, the new column by its declared name; using gives the new value from the old one). The verification fails the run unless reverse over every new value gives the old one back. ` +
|
|
311
|
+
`Or migrate one at a time: declare the rename with the old type, run the Op to its end, then change the type.`);
|
|
312
|
+
}
|
|
313
|
+
if (input.reverse !== undefined && !(rename && typeChange)) {
|
|
314
|
+
throw new MigrationRefusal(`${where}.${names.column}: reverse is for a rename combined with a type change, and this migration is ${rename ? "a rename only" : "a type change without a rename"}`);
|
|
315
|
+
}
|
|
316
|
+
if (input.reverse !== undefined && input.reverse.includes("$chant$")) {
|
|
317
|
+
throw new MigrationRefusal(`${where}: the reverse expression may not contain $chant$, which quotes the dual-write function's body`);
|
|
301
318
|
}
|
|
302
|
-
|
|
303
|
-
|
|
319
|
+
const hasDefault = source.default !== undefined || column.default !== undefined;
|
|
320
|
+
if (rename && typeChange && (hasDefault || source.identity || column.generated?.kind === "identity")) {
|
|
321
|
+
throw new MigrationRefusal(`${where}: ${source.name} has a default, serial or identity, and its rename also changes its type. The default is an expression of the old type; converting it, and the sequence's type, ` +
|
|
322
|
+
`is a third conversion on top of using and reverse that nothing verifies. Rename first (defaultAtContract: true), run the Op to its end, then change the type.`);
|
|
323
|
+
}
|
|
324
|
+
if (rename && (hasDefault || source.identity) && !input.defaultAtContract) {
|
|
325
|
+
throw new MigrationRefusal(`${where}: ${source.name} has a default (${source.default ?? column.default ?? "identity"}). During a rename both columns are written, each from the other, ` +
|
|
304
326
|
`and a row inserted by a writer that names one column would get the other's default, which the trigger cannot tell from a value it was given. ` +
|
|
305
|
-
`
|
|
327
|
+
`Set defaultAtContract: true to leave the new column without the default until the contract, which gives the default to the new column in the contract's transaction; ` +
|
|
328
|
+
`until then an INSERT that names the new column with an explicit NULL gets the default, and UPDATE ... SET <new> = DEFAULT sets NULL. Or drop the default first (the applier does), rename, then declare it again.`);
|
|
329
|
+
}
|
|
330
|
+
if (input.defaultAtContract && !(rename && (hasDefault || source.identity))) {
|
|
331
|
+
throw new MigrationRefusal(`${where}.${names.column}: defaultAtContract is for a rename of a column with a default, serial or identity, and this migration is not one`);
|
|
306
332
|
}
|
|
307
333
|
if (source.generated || (column.generated && column.generated.kind !== "identity")) {
|
|
308
334
|
throw new MigrationRefusal(`${where}.${source.name} is a generated column. There is no expand and contract for one: Postgres cannot make an existing column generated, so the new column could only be added generated, ` +
|
|
@@ -324,6 +350,7 @@ async function refuseUnsupported(input, names, rel, source, column, changes, ren
|
|
|
324
350
|
declared: input.declared,
|
|
325
351
|
defaultSchema: input.target.defaultSchema,
|
|
326
352
|
partitioned: rel.kind === "p",
|
|
353
|
+
...(input.defaultAtContract ? { keepSequence: true } : {}),
|
|
327
354
|
});
|
|
328
355
|
if (dependents.refused.length > 0) {
|
|
329
356
|
throw new MigrationRefusal(`${where}.${source.name} is used by what the migration Op does not carry over to the new column: ${dependents.refused.join("; ")}. ` +
|
|
@@ -351,6 +378,8 @@ export function migrationPlanSubject(o) {
|
|
|
351
378
|
from: o.source ? { name: o.source.name, type: o.source.type, notNull: o.source.notNull, default: o.source.default ?? null } : null,
|
|
352
379
|
to: { name: o.column.name, type: o.column.type ?? null, notNull: o.column.notNull === true, default: o.column.default ?? null, comment: o.column.comment ?? null },
|
|
353
380
|
expression: o.expression,
|
|
381
|
+
...(o.reverse !== undefined ? { reverse: o.reverse } : {}),
|
|
382
|
+
...(o.defaultAtContract ? { defaultAtContract: true } : {}),
|
|
354
383
|
batchKey: o.batchKey,
|
|
355
384
|
rules: o.changes.map((c) => c.rule),
|
|
356
385
|
...(o.carried.length > 0 || o.views.length > 0 || o.sequence ? { dependents: carriedSubject(o) } : {}),
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* | Expand | add the new column, nullable, no default (a catalog change) |
|
|
21
21
|
* | Dual write | a trigger that keeps the new column written: computed from the old one for a type change, both ways for a rename |
|
|
22
22
|
* | Backfill | `UPDATE` per key range, each batch with its receipt in its own transaction, under `lock_timeout`, pausing while a replica is behind |
|
|
23
|
-
* | Carry over | each index on the old column built again on the new one `CONCURRENTLY
|
|
23
|
+
* | Carry over | each index on the old column built again on the new one `CONCURRENTLY` (on a partitioned table: `ON ONLY` the table, `CONCURRENTLY` per partition, then attached), each check and foreign key (another table's too) added `NOT VALID` and validated (`./carry.ts`) |
|
|
24
24
|
* | Verify | rows, mismatches and checksums of the new column against the old |
|
|
25
25
|
* | Approve | a gate bound to the plan and the verified new column |
|
|
26
26
|
* | Switch | NOT NULL proven by a validated check; then one short transaction: a type change swaps the columns by name, a rename finishes the new column; the carried indexes and constraints take their names (keys `USING INDEX`), and the views that read the column are made again from their declarations |
|
|
@@ -60,6 +60,29 @@ export interface PostgresMigrationOpConfig {
|
|
|
60
60
|
* and the verification all use it.
|
|
61
61
|
*/
|
|
62
62
|
using?: string;
|
|
63
|
+
/**
|
|
64
|
+
* A rename combined with a type change: the SQL expression that gives the
|
|
65
|
+
* old column's value from the new column's, over the row's columns (the
|
|
66
|
+
* new column by its declared name). `using` gives the new value from the
|
|
67
|
+
* old one. Both stay in force until the contract: a writer of the old name
|
|
68
|
+
* has `using` applied, a writer of the new name has `reverse` applied. The
|
|
69
|
+
* verification fails the run unless `reverse` over every new value gives
|
|
70
|
+
* the old value back. A new value the old type cannot hold fails the
|
|
71
|
+
* writer's statement until the contract drops the old column.
|
|
72
|
+
*/
|
|
73
|
+
reverse?: string;
|
|
74
|
+
/**
|
|
75
|
+
* A rename of a column with a default, an identity or a serial sequence.
|
|
76
|
+
* The declared default (or identity, or the serial's default) lands on the
|
|
77
|
+
* new column at the contract, not at the switch, so that until then a
|
|
78
|
+
* writer of either name gets the old column's default once. Two writes
|
|
79
|
+
* differ from the declaration until then, and `true` accepts both: an
|
|
80
|
+
* INSERT that names the new column with an explicit NULL gets the default
|
|
81
|
+
* instead of NULL, and `UPDATE ... SET <new> = DEFAULT` sets NULL. An
|
|
82
|
+
* `ApplyOp` between the switch and the contract must not set the default
|
|
83
|
+
* on the new column. Needs `gates: "own"` to end with the contract.
|
|
84
|
+
*/
|
|
85
|
+
defaultAtContract?: boolean;
|
|
63
86
|
/** The build output the declaration is read from. Default: `dist/schema.json`. */
|
|
64
87
|
output?: string;
|
|
65
88
|
/** Project directory to build. Default: `.`. */
|
|
@@ -139,6 +162,8 @@ export interface PostgresMigrationArgs {
|
|
|
139
162
|
buildPath: string;
|
|
140
163
|
environment?: string;
|
|
141
164
|
using?: string;
|
|
165
|
+
reverse?: string;
|
|
166
|
+
defaultAtContract?: boolean;
|
|
142
167
|
retain?: string;
|
|
143
168
|
batchSize?: number;
|
|
144
169
|
replicationLag?: {
|