@intentius/chant-lexicon-sql 0.124.46 → 0.124.49
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/statements.d.ts +29 -0
- package/dist/clickhouse/plan/statements.d.ts.map +1 -0
- package/dist/clickhouse/plan/statements.js +334 -0
- 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 +44 -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 +2 -2
- package/dist/codegen/registry.d.ts.map +1 -1
- package/dist/codegen/registry.js +10 -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/core/statement-class.d.ts +55 -0
- package/dist/core/statement-class.d.ts.map +1 -0
- package/dist/core/statement-class.js +43 -0
- package/dist/coverage/clickhouse.json +1 -1
- package/dist/coverage/postgres.json +12 -12
- 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 +689 -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.d.ts.map +1 -1
- package/dist/files/postgres.js +35 -3
- 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 +7 -6
- 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/postgres-names.d.ts.map +1 -1
- package/dist/lint/post-synth/postgres-names.js +3 -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 +21 -0
- package/dist/manifest.json +1 -1
- package/dist/mcp/postgres.js +1 -1
- package/dist/meta.json +50 -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-classify.d.ts +23 -0
- package/dist/migration-classify.d.ts.map +1 -0
- package/dist/migration-classify.js +44 -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 +11 -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/PostgresForeignTable.md +9 -0
- package/dist/okf/types/PostgresOperator.md +9 -0
- package/dist/okf/types/PostgresOperatorClass.md +9 -0
- package/dist/okf/types/PostgresOperatorFamily.md +9 -0
- package/dist/okf/types/PostgresPublication.md +9 -0
- package/dist/okf/types/PostgresStatistics.md +9 -0
- package/dist/okf/types/PostgresTextSearchConfiguration.md +9 -0
- package/dist/okf/types/PostgresTextSearchDictionary.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 +49 -2
- package/dist/postgres/access/acl.js +1 -1
- package/dist/postgres/access/import.js +1 -1
- package/dist/postgres/apply/apply.js +13 -1
- package/dist/postgres/apply/statements.d.ts.map +1 -1
- package/dist/postgres/apply/statements.js +243 -4
- 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 +229 -2
- package/dist/postgres/entities.d.ts.map +1 -1
- package/dist/postgres/entities.js +326 -5
- package/dist/postgres/entity-types.d.ts +10 -0
- package/dist/postgres/entity-types.d.ts.map +1 -1
- package/dist/postgres/entity-types.js +10 -0
- package/dist/postgres/import/generator.d.ts.map +1 -1
- package/dist/postgres/import/generator.js +65 -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 +20 -0
- package/dist/postgres/live/catalog-kinds.d.ts.map +1 -1
- package/dist/postgres/live/catalog-kinds.js +452 -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 +12 -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 +45 -13
- 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/replication.d.ts +42 -0
- package/dist/postgres/migrate/replication.d.ts.map +1 -1
- package/dist/postgres/migrate/replication.js +53 -0
- 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 +144 -1
- package/dist/postgres/parser.d.ts.map +1 -1
- package/dist/postgres/parser.js +370 -4
- package/dist/postgres/plan/deep.d.ts.map +1 -1
- package/dist/postgres/plan/deep.js +43 -4
- package/dist/postgres/plan/diff.d.ts.map +1 -1
- package/dist/postgres/plan/diff.js +154 -1
- package/dist/postgres/plan/normalize.d.ts +28 -2
- package/dist/postgres/plan/normalize.d.ts.map +1 -1
- package/dist/postgres/plan/normalize.js +260 -1
- package/dist/postgres/plan/rules.d.ts +4 -0
- package/dist/postgres/plan/rules.d.ts.map +1 -1
- package/dist/postgres/plan/rules.js +6 -2
- package/dist/postgres/plan/schema.js +1 -1
- package/dist/postgres/plan/statements.d.ts +26 -0
- package/dist/postgres/plan/statements.d.ts.map +1 -0
- package/dist/postgres/plan/statements.js +364 -0
- 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 +4 -2
- package/dist/postgres/testing/roundtrip-schema.d.ts.map +1 -1
- package/dist/postgres/testing/roundtrip-schema.js +24 -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-names.ts +2 -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 +10 -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/statements.test.ts +61 -0
- package/src/clickhouse/plan/statements.ts +306 -0
- 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 +44 -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 +2 -2
- package/src/codegen/registry.ts +10 -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/statement-class.ts +88 -0
- package/src/core/undeclarable.test.ts +6 -5
- package/src/coverage/clickhouse.json +1 -1
- package/src/coverage/postgres.json +12 -12
- 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 +742 -0
- package/src/files/clickhouse.ts +8 -1
- package/src/files/common.ts +14 -1
- package/src/files/postgres.ts +34 -3
- package/src/generated/clickhouse.ts +3 -0
- package/src/generated/lexicon-sql.json +50 -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/postgres-checks.test.ts +8 -1
- package/src/lint/post-synth/postgres-names.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 +20 -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-classify.test.ts +150 -0
- package/src/migration-classify.ts +45 -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/op/watch-pipeline.test.ts +8 -1
- package/src/plugin.ts +51 -2
- package/src/postgres/access/acl.ts +1 -1
- package/src/postgres/access/import.ts +1 -1
- package/src/postgres/apply/apply.ts +14 -1
- package/src/postgres/apply/statements.ts +225 -4
- package/src/postgres/constraint-names.ts +71 -0
- package/src/postgres/database-kinds.test.ts +865 -0
- package/src/postgres/entities.ts +541 -5
- package/src/postgres/entity-types.ts +10 -0
- package/src/postgres/import/generator.ts +54 -2
- package/src/postgres/import/live-export.ts +1 -0
- package/src/postgres/live/catalog-kinds.ts +494 -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 +13 -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 +56 -15
- 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/replication.ts +66 -0
- package/src/postgres/migrate/steps.ts +157 -12
- package/src/postgres/migrate/subscriber.e2e.test.ts +141 -0
- package/src/postgres/migrate/subscriber.test.ts +59 -0
- package/src/postgres/parser.ts +455 -4
- package/src/postgres/plan/deep.ts +42 -4
- package/src/postgres/plan/diff.ts +137 -1
- package/src/postgres/plan/normalize.ts +277 -1
- package/src/postgres/plan/rules.ts +32 -4
- package/src/postgres/plan/schema.ts +1 -1
- package/src/postgres/plan/statements.test.ts +78 -0
- package/src/postgres/plan/statements.ts +299 -0
- package/src/postgres/secret-options.ts +10 -0
- package/src/postgres/testing/roundtrip-schema.ts +24 -1
- package/src/postgres.ts +33 -0
- package/src/serializer.ts +13 -2
- package/src/skills/chant-sql-postgres-migration.md +4 -3
- package/src/skills/chant-sql-postgres.md +11 -1
- package/src/skills/chant-sql.md +2 -1
- package/src/sql-files.test.ts +33 -0
- 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 +10 -0
- package/src/workspace-kinds.test.ts +11 -0
- package/workspace-kinds.json +100 -2
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The needs-review catalog: the judgment calls that turn a table from another
|
|
3
|
+
* database into a ClickHouse table, each as a finding with the evidence it
|
|
4
|
+
* used. A source reader (`chant import` of SQL Server, #4398; `chant migrate`
|
|
5
|
+
* of Postgres, #4399) does the mechanical work, a type map and a rename,
|
|
6
|
+
* and asks this module for everything that is a decision.
|
|
7
|
+
*
|
|
8
|
+
* Nothing here knows a source dialect. A reader describes its table in the
|
|
9
|
+
* neutral facts below (a candidate sort key, a column's nullability, a
|
|
10
|
+
* constraint) and gets back the ClickHouse choice, a finding to report, and
|
|
11
|
+
* for a constraint the comment lines to keep in the DDL. The rules are the
|
|
12
|
+
* same whichever database the table came from.
|
|
13
|
+
*
|
|
14
|
+
* ## API
|
|
15
|
+
*
|
|
16
|
+
* - {@link sortKeyReview}: `ORDER BY` from the candidates the source offers,
|
|
17
|
+
* in the priority `explicit-order`, `clustering-key`, `primary-key`,
|
|
18
|
+
* `unique-key`, then `tuple()`. Returns `orderBy`, the `settings` the key
|
|
19
|
+
* needs (`allow_nullable_key` when a key column is `Nullable`), and a
|
|
20
|
+
* finding that names the chosen candidate and the others it passed over.
|
|
21
|
+
* - {@link engineReview}: `MergeTree` for an append-only table;
|
|
22
|
+
* `ReplacingMergeTree(_version, _deleted)` for a CDC mirror, with the two
|
|
23
|
+
* columns it adds in `extraColumns`. `cdcColumns` names them otherwise
|
|
24
|
+
* (the Postgres pair uses the `CdcMirror` composite's `_is_deleted`).
|
|
25
|
+
* - {@link nullableReview}: a column's final type. A `NOT NULL` column keeps
|
|
26
|
+
* its type with no finding. A nullable column becomes `Nullable(T)` with a
|
|
27
|
+
* finding; when it has a default the finding says the default could
|
|
28
|
+
* replace `Nullable`.
|
|
29
|
+
* - {@link lowCardinalityReview}: a finding for a `String` column whose name
|
|
30
|
+
* and declared length suggest few distinct values. It never changes the
|
|
31
|
+
* type; offline, the name and the type are all there is to read.
|
|
32
|
+
* - {@link constraintReview}: foreign keys, checks, unique and exclusion
|
|
33
|
+
* constraints, which ClickHouse does not enforce. Returns `comments` (SQL `--` lines to
|
|
34
|
+
* put before the `CREATE`) and one finding per constraint.
|
|
35
|
+
* - {@link REVIEW_RULES}: every rule id with its summary and the ClickHouse
|
|
36
|
+
* documentation it rests on, for report metadata.
|
|
37
|
+
* - {@link findingText}: a finding as one line (object, message, evidence,
|
|
38
|
+
* suggestion), the form a SARIF `message` takes.
|
|
39
|
+
*
|
|
40
|
+
* A finding's `severity` is `warning` for a decision the author must confirm
|
|
41
|
+
* and `info` for a note that changes nothing. The caller maps findings to its
|
|
42
|
+
* own diagnostic type; `at` carries the source line and column when the
|
|
43
|
+
* reader knows them.
|
|
44
|
+
*
|
|
45
|
+
* Every ClickHouse type and engine this module writes is checked against the
|
|
46
|
+
* pinned catalog (`src/generated/clickhouse.ts`, ClickHouse 26.8) in
|
|
47
|
+
* `review-catalog.test.ts`, so a pin move that drops one fails there.
|
|
48
|
+
*
|
|
49
|
+
* Sources: the MergeTree sorting key and `allow_nullable_key`
|
|
50
|
+
* (https://clickhouse.com/docs/engines/table-engines/mergetree-family/mergetree),
|
|
51
|
+
* `ReplacingMergeTree(ver, is_deleted)`
|
|
52
|
+
* (https://clickhouse.com/docs/engines/table-engines/mergetree-family/replacingmergetree),
|
|
53
|
+
* `Nullable` (https://clickhouse.com/docs/sql-reference/data-types/nullable),
|
|
54
|
+
* `LowCardinality`
|
|
55
|
+
* (https://clickhouse.com/docs/sql-reference/data-types/lowcardinality).
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
export type ReviewSeverity = "warning" | "info";
|
|
59
|
+
|
|
60
|
+
export type ReviewRuleId =
|
|
61
|
+
| "SQLRV001"
|
|
62
|
+
| "SQLRV002"
|
|
63
|
+
| "SQLRV003"
|
|
64
|
+
| "SQLRV004"
|
|
65
|
+
| "SQLRV005"
|
|
66
|
+
| "SQLRV006"
|
|
67
|
+
| "SQLRV007"
|
|
68
|
+
| "SQLRV008"
|
|
69
|
+
| "SQLRV009"
|
|
70
|
+
| "SQLRV010"
|
|
71
|
+
| "SQLRV011"
|
|
72
|
+
| "SQLRV012";
|
|
73
|
+
|
|
74
|
+
export interface ReviewRule {
|
|
75
|
+
id: ReviewRuleId;
|
|
76
|
+
name: string;
|
|
77
|
+
summary: string;
|
|
78
|
+
docs: readonly string[];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const CH_MERGETREE = "https://clickhouse.com/docs/engines/table-engines/mergetree-family/mergetree";
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The rules. SQLRV001 to SQLRV005 are the shared ones; the rest are raised by
|
|
85
|
+
* a source reader for what only its dialect has, and live here so a report
|
|
86
|
+
* lists one catalog.
|
|
87
|
+
*/
|
|
88
|
+
export const REVIEW_RULES: Readonly<Record<ReviewRuleId, ReviewRule>> = {
|
|
89
|
+
SQLRV001: {
|
|
90
|
+
id: "SQLRV001",
|
|
91
|
+
name: "sort-key",
|
|
92
|
+
summary: "The ORDER BY key is a suggestion from the source's indexes.",
|
|
93
|
+
docs: [CH_MERGETREE],
|
|
94
|
+
},
|
|
95
|
+
SQLRV002: {
|
|
96
|
+
id: "SQLRV002",
|
|
97
|
+
name: "engine",
|
|
98
|
+
summary: "The table engine is a choice the source does not make.",
|
|
99
|
+
docs: [CH_MERGETREE, "https://clickhouse.com/docs/engines/table-engines/mergetree-family/replacingmergetree"],
|
|
100
|
+
},
|
|
101
|
+
SQLRV003: {
|
|
102
|
+
id: "SQLRV003",
|
|
103
|
+
name: "nullable",
|
|
104
|
+
summary: "A nullable column becomes Nullable(T), which costs storage and speed; a default can replace it.",
|
|
105
|
+
docs: ["https://clickhouse.com/docs/sql-reference/data-types/nullable"],
|
|
106
|
+
},
|
|
107
|
+
SQLRV004: {
|
|
108
|
+
id: "SQLRV004",
|
|
109
|
+
name: "low-cardinality",
|
|
110
|
+
summary: "A String column that may hold few distinct values could be LowCardinality(String).",
|
|
111
|
+
docs: ["https://clickhouse.com/docs/sql-reference/data-types/lowcardinality"],
|
|
112
|
+
},
|
|
113
|
+
SQLRV005: {
|
|
114
|
+
id: "SQLRV005",
|
|
115
|
+
name: "constraint",
|
|
116
|
+
summary: "ClickHouse does not enforce this constraint; it is kept as a comment.",
|
|
117
|
+
docs: ["https://clickhouse.com/docs/sql-reference/statements/create/table"],
|
|
118
|
+
},
|
|
119
|
+
SQLRV006: {
|
|
120
|
+
id: "SQLRV006",
|
|
121
|
+
name: "generated-column",
|
|
122
|
+
summary: "An identity, sequence, computed or system-generated column has no ClickHouse equivalent.",
|
|
123
|
+
docs: ["https://clickhouse.com/docs/sql-reference/statements/create/table"],
|
|
124
|
+
},
|
|
125
|
+
SQLRV007: {
|
|
126
|
+
id: "SQLRV007",
|
|
127
|
+
name: "type-judgment",
|
|
128
|
+
summary: "The type has no exact ClickHouse match; the nearest one was chosen.",
|
|
129
|
+
docs: ["https://clickhouse.com/docs/sql-reference/data-types"],
|
|
130
|
+
},
|
|
131
|
+
SQLRV008: {
|
|
132
|
+
id: "SQLRV008",
|
|
133
|
+
name: "default-expression",
|
|
134
|
+
summary: "A default expression was translated or dropped.",
|
|
135
|
+
docs: ["https://clickhouse.com/docs/sql-reference/statements/create/table"],
|
|
136
|
+
},
|
|
137
|
+
SQLRV009: {
|
|
138
|
+
id: "SQLRV009",
|
|
139
|
+
name: "storage-option",
|
|
140
|
+
summary: "A storage option of the source (filegroup, partitioning, compression, versioning) has no counterpart here.",
|
|
141
|
+
docs: [CH_MERGETREE],
|
|
142
|
+
},
|
|
143
|
+
SQLRV010: {
|
|
144
|
+
id: "SQLRV010",
|
|
145
|
+
name: "query-text",
|
|
146
|
+
summary: "A view body is copied as written and is not translated.",
|
|
147
|
+
docs: ["https://clickhouse.com/docs/sql-reference/statements/create/view"],
|
|
148
|
+
},
|
|
149
|
+
SQLRV011: {
|
|
150
|
+
id: "SQLRV011",
|
|
151
|
+
name: "not-carried",
|
|
152
|
+
summary: "An object or statement of the source is not carried over, and is named here.",
|
|
153
|
+
docs: [],
|
|
154
|
+
},
|
|
155
|
+
SQLRV012: {
|
|
156
|
+
id: "SQLRV012",
|
|
157
|
+
name: "emulator-rejected",
|
|
158
|
+
summary: "The ClickHouse emulator refused a statement the import would write.",
|
|
159
|
+
docs: [],
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export interface SourcePosition {
|
|
164
|
+
/** 1-based. */
|
|
165
|
+
line: number;
|
|
166
|
+
/** 1-based. */
|
|
167
|
+
column: number;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface ReviewFinding {
|
|
171
|
+
ruleId: ReviewRuleId;
|
|
172
|
+
severity: ReviewSeverity;
|
|
173
|
+
/** The table or view the finding is about, as the source names it. */
|
|
174
|
+
object: string;
|
|
175
|
+
/** The column, when the finding is about one. */
|
|
176
|
+
column?: string;
|
|
177
|
+
message: string;
|
|
178
|
+
/** What the decision was read from: each entry is a fact in the source. */
|
|
179
|
+
evidence: readonly string[];
|
|
180
|
+
suggestion?: string;
|
|
181
|
+
at?: SourcePosition;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** A finding as one line. */
|
|
185
|
+
export function findingText(f: ReviewFinding): string {
|
|
186
|
+
const where = f.column ? `${f.object}.${f.column}` : f.object;
|
|
187
|
+
const parts = [`${where}: ${f.message}`];
|
|
188
|
+
if (f.evidence.length > 0) parts.push(`Evidence: ${f.evidence.join("; ")}.`);
|
|
189
|
+
if (f.suggestion) parts.push(`Suggestion: ${f.suggestion}`);
|
|
190
|
+
return parts.join(" ");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const q = (name: string): string => (/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `\`${name.replace(/`/g, "\\`")}\``);
|
|
194
|
+
const list = (names: readonly string[]): string => names.join(", ");
|
|
195
|
+
|
|
196
|
+
// --- sort key -------------------------------------------------------------
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Where a candidate sort key came from, strongest first. `explicit-order` is
|
|
200
|
+
* an ordering the author declared for storage (a columnstore `ORDER`),
|
|
201
|
+
* `clustering-key` the key the source stores rows in (a clustered index),
|
|
202
|
+
* then the primary key and the first unique key.
|
|
203
|
+
*/
|
|
204
|
+
export type SortKeyKind = "explicit-order" | "clustering-key" | "primary-key" | "unique-key";
|
|
205
|
+
|
|
206
|
+
const SORT_KEY_PRIORITY: readonly SortKeyKind[] = ["explicit-order", "clustering-key", "primary-key", "unique-key"];
|
|
207
|
+
|
|
208
|
+
export interface SortKeyCandidate {
|
|
209
|
+
kind: SortKeyKind;
|
|
210
|
+
/** The index or constraint name, for the evidence. */
|
|
211
|
+
name?: string;
|
|
212
|
+
columns: readonly string[];
|
|
213
|
+
/** Columns the source sorts descending; ClickHouse's `ORDER BY` drops the direction. */
|
|
214
|
+
descending?: readonly string[];
|
|
215
|
+
/** The fact this candidate was read from, e.g. `CREATE CLUSTERED INDEX CX_t`. */
|
|
216
|
+
source: string;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export interface SortKeyInput {
|
|
220
|
+
object: string;
|
|
221
|
+
candidates: readonly SortKeyCandidate[];
|
|
222
|
+
/** Each column's ClickHouse type, by name; `Nullable(...)` marks a nullable key column. */
|
|
223
|
+
columnTypes: Readonly<Record<string, string>>;
|
|
224
|
+
at?: SourcePosition;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export interface SortKeyResult {
|
|
228
|
+
orderBy: string[];
|
|
229
|
+
/** MergeTree settings the key needs. */
|
|
230
|
+
settings: Record<string, string>;
|
|
231
|
+
finding: ReviewFinding;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function sortKeyReview(input: SortKeyInput): SortKeyResult {
|
|
235
|
+
const ranked = SORT_KEY_PRIORITY.flatMap((kind) => input.candidates.filter((c) => c.kind === kind && c.columns.length > 0));
|
|
236
|
+
const chosen = ranked[0];
|
|
237
|
+
const evidence: string[] = [];
|
|
238
|
+
const settings: Record<string, string> = {};
|
|
239
|
+
let orderBy: string[] = [];
|
|
240
|
+
let message: string;
|
|
241
|
+
let suggestion: string | undefined;
|
|
242
|
+
if (chosen) {
|
|
243
|
+
orderBy = [...chosen.columns];
|
|
244
|
+
evidence.push(`${chosen.source} (${list(chosen.columns)})`);
|
|
245
|
+
for (const other of ranked.slice(1)) evidence.push(`passed over: ${other.source} (${list(other.columns)})`);
|
|
246
|
+
if (chosen.descending && chosen.descending.length > 0) evidence.push(`descending in the source, ascending here: ${list(chosen.descending)}`);
|
|
247
|
+
const nullable = orderBy.filter((c) => (input.columnTypes[c] ?? "").startsWith("Nullable("));
|
|
248
|
+
if (nullable.length > 0) {
|
|
249
|
+
settings.allow_nullable_key = "1";
|
|
250
|
+
evidence.push(`Nullable key column${nullable.length > 1 ? "s" : ""}: ${list(nullable)}, so allow_nullable_key = 1 is set`);
|
|
251
|
+
}
|
|
252
|
+
message = `ORDER BY (${list(orderBy.map(q))}) suggested from the ${chosen.kind.replace("-", " ")}.`;
|
|
253
|
+
suggestion = "Put the columns your queries filter on first, and the one with the fewest distinct values before the one with the most.";
|
|
254
|
+
} else {
|
|
255
|
+
orderBy = [];
|
|
256
|
+
evidence.push("no clustering key, primary key or unique key in the source");
|
|
257
|
+
message = "ORDER BY tuple() used because the source gives no key to suggest.";
|
|
258
|
+
suggestion = "Choose the columns your queries filter on; a MergeTree table without a sort key cannot skip granules.";
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
orderBy,
|
|
262
|
+
settings,
|
|
263
|
+
finding: { ruleId: "SQLRV001", severity: "warning", object: input.object, message, evidence, ...(suggestion ? { suggestion } : {}), ...(input.at ? { at: input.at } : {}) },
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// --- engine ---------------------------------------------------------------
|
|
268
|
+
|
|
269
|
+
export interface EngineInput {
|
|
270
|
+
object: string;
|
|
271
|
+
/**
|
|
272
|
+
* `append` for a table that is loaded and queried, `cdc` for a mirror of a
|
|
273
|
+
* table that changes in place (#4399): rows arrive as new versions and a
|
|
274
|
+
* delete arrives as a marker row.
|
|
275
|
+
*/
|
|
276
|
+
mode: "append" | "cdc";
|
|
277
|
+
/** Facts about the source table that bear on the choice, as plain sentences. */
|
|
278
|
+
facts?: readonly string[];
|
|
279
|
+
/** The columns the source enforces unique, when it does. */
|
|
280
|
+
uniqueKey?: readonly string[];
|
|
281
|
+
/**
|
|
282
|
+
* For `cdc`, the names of the version and deleted columns, when the pipeline
|
|
283
|
+
* or the `CdcMirror` composite names them other than `_version` and
|
|
284
|
+
* `_deleted`. The names are the caller's; the catalog only writes them.
|
|
285
|
+
*/
|
|
286
|
+
cdcColumns?: { version: string; deleted: string };
|
|
287
|
+
at?: SourcePosition;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export interface EngineResult {
|
|
291
|
+
/** The text after `ENGINE =`. */
|
|
292
|
+
engine: string;
|
|
293
|
+
/** Columns the engine needs and the source does not have. */
|
|
294
|
+
extraColumns: Array<{ name: string; type: string }>;
|
|
295
|
+
finding: ReviewFinding;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export const CDC_VERSION_COLUMN = { name: "_version", type: "UInt64" } as const;
|
|
299
|
+
export const CDC_DELETED_COLUMN = { name: "_deleted", type: "UInt8" } as const;
|
|
300
|
+
|
|
301
|
+
export function engineReview(input: EngineInput): EngineResult {
|
|
302
|
+
const evidence = [...(input.facts ?? [])];
|
|
303
|
+
const unique = input.uniqueKey && input.uniqueKey.length > 0 ? list(input.uniqueKey) : undefined;
|
|
304
|
+
if (input.mode === "cdc") {
|
|
305
|
+
evidence.push(`the table is mirrored from a source that updates rows in place${unique ? `, keyed on (${unique})` : ""}`);
|
|
306
|
+
const version = input.cdcColumns?.version ?? CDC_VERSION_COLUMN.name;
|
|
307
|
+
const deleted = input.cdcColumns?.deleted ?? CDC_DELETED_COLUMN.name;
|
|
308
|
+
return {
|
|
309
|
+
engine: `ReplacingMergeTree(${version}, ${deleted})`,
|
|
310
|
+
extraColumns: [
|
|
311
|
+
{ name: version, type: CDC_VERSION_COLUMN.type },
|
|
312
|
+
{ name: deleted, type: CDC_DELETED_COLUMN.type },
|
|
313
|
+
],
|
|
314
|
+
finding: {
|
|
315
|
+
ruleId: "SQLRV002",
|
|
316
|
+
severity: "warning",
|
|
317
|
+
object: input.object,
|
|
318
|
+
message: `ReplacingMergeTree(${version}, ${deleted}) chosen for a mirror; it adds the columns ${version} and ${deleted}.`,
|
|
319
|
+
evidence,
|
|
320
|
+
suggestion: `The sort key must be the source key, because rows with an equal sort key collapse to the highest ${version} on merge. Read with FINAL, or filter on ${deleted}, to see the collapsed rows before a merge.`,
|
|
321
|
+
...(input.at ? { at: input.at } : {}),
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
if (unique) evidence.push(`the source enforces uniqueness on (${unique}); MergeTree does not`);
|
|
326
|
+
return {
|
|
327
|
+
engine: "MergeTree",
|
|
328
|
+
extraColumns: [],
|
|
329
|
+
finding: {
|
|
330
|
+
ruleId: "SQLRV002",
|
|
331
|
+
severity: "warning",
|
|
332
|
+
object: input.object,
|
|
333
|
+
message: "MergeTree chosen; the source has no engine to carry over.",
|
|
334
|
+
evidence,
|
|
335
|
+
suggestion: unique
|
|
336
|
+
? "If rows can arrive twice, ReplacingMergeTree collapses duplicates of the sort key on merge, not on insert."
|
|
337
|
+
: "Pick another MergeTree variant for pre-aggregation (SummingMergeTree, AggregatingMergeTree) when the table is a rollup.",
|
|
338
|
+
...(input.at ? { at: input.at } : {}),
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// --- Nullable -------------------------------------------------------------
|
|
344
|
+
|
|
345
|
+
export interface NullableInput {
|
|
346
|
+
object: string;
|
|
347
|
+
column: string;
|
|
348
|
+
/** The column's ClickHouse type before `Nullable`. */
|
|
349
|
+
type: string;
|
|
350
|
+
sourceNullable: boolean;
|
|
351
|
+
/** The default as the ClickHouse expression it became, or the source text when it did not translate. */
|
|
352
|
+
defaultExpr?: string;
|
|
353
|
+
at?: SourcePosition;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export interface NullableResult {
|
|
357
|
+
type: string;
|
|
358
|
+
finding?: ReviewFinding;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export function nullableReview(input: NullableInput): NullableResult {
|
|
362
|
+
if (!input.sourceNullable) return { type: input.type };
|
|
363
|
+
const evidence = [`${input.column} allows NULL in the source`];
|
|
364
|
+
let suggestion: string;
|
|
365
|
+
if (input.defaultExpr !== undefined) {
|
|
366
|
+
evidence.push(`it has the default ${input.defaultExpr}`);
|
|
367
|
+
suggestion = `If NULL is never stored on purpose, declare ${input.type} DEFAULT ${input.defaultExpr} and load the default instead of NULL.`;
|
|
368
|
+
} else {
|
|
369
|
+
evidence.push("it has no default");
|
|
370
|
+
suggestion = `If a sentinel value can stand for missing, declare ${input.type} DEFAULT <sentinel>; a Nullable column keeps a separate null mask.`;
|
|
371
|
+
}
|
|
372
|
+
return {
|
|
373
|
+
type: `Nullable(${input.type})`,
|
|
374
|
+
finding: {
|
|
375
|
+
ruleId: "SQLRV003",
|
|
376
|
+
severity: "warning",
|
|
377
|
+
object: input.object,
|
|
378
|
+
column: input.column,
|
|
379
|
+
message: `Kept as Nullable(${input.type}) so no stored NULL is lost.`,
|
|
380
|
+
evidence,
|
|
381
|
+
suggestion,
|
|
382
|
+
...(input.at ? { at: input.at } : {}),
|
|
383
|
+
},
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// --- LowCardinality -------------------------------------------------------
|
|
388
|
+
|
|
389
|
+
/** Last words of a column name that usually mean a small set of values. */
|
|
390
|
+
const LOW_CARDINALITY_WORDS = new Set("status state type kind category country currency region level channel gender lang language locale unit code flag method mode grade tier priority".split(" "));
|
|
391
|
+
|
|
392
|
+
/** A column name's last word: `order_status` and `OrderStatus` both give `status`. */
|
|
393
|
+
function lastWord(name: string): string {
|
|
394
|
+
const words = name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
395
|
+
return (words[words.length - 1] ?? "").toLowerCase();
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export interface LowCardinalityInput {
|
|
399
|
+
object: string;
|
|
400
|
+
column: string;
|
|
401
|
+
/** The ClickHouse type as emitted. Only `String` and `Nullable(String)` are candidates. */
|
|
402
|
+
type: string;
|
|
403
|
+
/** The source's declared maximum length, when it has one. */
|
|
404
|
+
maxLength?: number;
|
|
405
|
+
at?: SourcePosition;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/** The longest declared length that still counts as supporting evidence. */
|
|
409
|
+
export const LOW_CARDINALITY_MAX_LENGTH = 50;
|
|
410
|
+
|
|
411
|
+
export function lowCardinalityReview(input: LowCardinalityInput): ReviewFinding | undefined {
|
|
412
|
+
if (input.type !== "String" && input.type !== "Nullable(String)") return undefined;
|
|
413
|
+
if (!LOW_CARDINALITY_WORDS.has(lastWord(input.column))) return undefined;
|
|
414
|
+
const evidence = [`the name ${input.column} ends in a word that usually names a small set of values`, `the type is ${input.type}`];
|
|
415
|
+
if (input.maxLength !== undefined && input.maxLength <= LOW_CARDINALITY_MAX_LENGTH) evidence.push(`the declared length is ${String(input.maxLength)}`);
|
|
416
|
+
evidence.push("no data was read, so the distinct count is unknown");
|
|
417
|
+
const wrapped = input.type.startsWith("Nullable(") ? "LowCardinality(Nullable(String))" : "LowCardinality(String)";
|
|
418
|
+
return {
|
|
419
|
+
ruleId: "SQLRV004",
|
|
420
|
+
severity: "warning",
|
|
421
|
+
object: input.object,
|
|
422
|
+
column: input.column,
|
|
423
|
+
message: `${input.column} is a LowCardinality candidate and stays ${input.type}.`,
|
|
424
|
+
evidence,
|
|
425
|
+
suggestion: `ClickHouse documents ${wrapped} as helpful below roughly ten thousand distinct values; count them with uniqExact(${q(input.column)}) before changing the type.`,
|
|
426
|
+
...(input.at ? { at: input.at } : {}),
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// --- constraints ----------------------------------------------------------
|
|
431
|
+
|
|
432
|
+
export interface ConstraintFact {
|
|
433
|
+
kind: "foreign-key" | "check" | "unique" | "exclusion";
|
|
434
|
+
name?: string;
|
|
435
|
+
columns?: readonly string[];
|
|
436
|
+
references?: { table: string; columns: readonly string[] };
|
|
437
|
+
/** A check's expression, or an exclusion's `USING method (element WITH operator, ...)`, as the source wrote it. */
|
|
438
|
+
expression?: string;
|
|
439
|
+
at?: SourcePosition;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
export interface ConstraintResult {
|
|
443
|
+
/** `-- ` lines to put before the `CREATE`; never contain a line break. */
|
|
444
|
+
comments: string[];
|
|
445
|
+
findings: ReviewFinding[];
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const oneLine = (s: string): string => s.replace(/\s+/g, " ").trim();
|
|
449
|
+
|
|
450
|
+
export function constraintReview(input: { object: string; constraints: readonly ConstraintFact[] }): ConstraintResult {
|
|
451
|
+
const comments: string[] = [];
|
|
452
|
+
const findings: ReviewFinding[] = [];
|
|
453
|
+
for (const c of input.constraints) {
|
|
454
|
+
const label = c.name ? ` ${c.name}` : "";
|
|
455
|
+
let text: string;
|
|
456
|
+
let message: string;
|
|
457
|
+
let suggestion: string;
|
|
458
|
+
if (c.kind === "foreign-key") {
|
|
459
|
+
const target = c.references ? `${c.references.table} (${list(c.references.columns)})` : "an unknown table";
|
|
460
|
+
text = `FOREIGN KEY${label} (${list(c.columns ?? [])}) REFERENCES ${target}`;
|
|
461
|
+
message = `Foreign key${label} is not enforced by ClickHouse and is kept as a comment.`;
|
|
462
|
+
suggestion = "Check referential integrity in the load pipeline, or join on the column and accept orphan rows.";
|
|
463
|
+
} else if (c.kind === "unique") {
|
|
464
|
+
text = `UNIQUE${label} (${list(c.columns ?? [])})`;
|
|
465
|
+
message = `Unique constraint${label} is not enforced by ClickHouse and is kept as a comment.`;
|
|
466
|
+
suggestion = "A MergeTree sort key does not make rows unique. ReplacingMergeTree collapses duplicates on merge only.";
|
|
467
|
+
} else if (c.kind === "exclusion") {
|
|
468
|
+
text = `EXCLUDE${label} ${oneLine(c.expression ?? "")}`;
|
|
469
|
+
message = `Exclusion constraint${label} is not enforced by ClickHouse and is kept as a comment.`;
|
|
470
|
+
suggestion = "ClickHouse has no constraint that rejects overlapping rows. Check for overlaps in the load, or in a query.";
|
|
471
|
+
} else {
|
|
472
|
+
text = `CHECK${label} ${oneLine(c.expression ?? "")}`;
|
|
473
|
+
message = `Check constraint${label} is not translated and is kept as a comment.`;
|
|
474
|
+
suggestion = "ClickHouse has CONSTRAINT name CHECK expr, enforced on INSERT. Rewrite the expression in ClickHouse SQL to use it.";
|
|
475
|
+
}
|
|
476
|
+
comments.push(`-- ${oneLine(text)}`);
|
|
477
|
+
findings.push({
|
|
478
|
+
ruleId: "SQLRV005",
|
|
479
|
+
severity: "warning",
|
|
480
|
+
object: input.object,
|
|
481
|
+
...(c.kind !== "check" && c.kind !== "exclusion" && c.columns && c.columns.length === 1 ? { column: c.columns[0]! } : {}),
|
|
482
|
+
message,
|
|
483
|
+
evidence: [oneLine(text)],
|
|
484
|
+
suggestion,
|
|
485
|
+
...(c.at ? { at: c.at } : {}),
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
return { comments, findings };
|
|
489
|
+
}
|
|
@@ -10,6 +10,7 @@ const LABEL: Record<string, string> = {
|
|
|
10
10
|
drop: "drop",
|
|
11
11
|
metadata: "metadata only",
|
|
12
12
|
rewrite: "background rewrite",
|
|
13
|
+
replace: "replace table",
|
|
13
14
|
rebuild: "rebuild",
|
|
14
15
|
};
|
|
15
16
|
|
|
@@ -22,7 +23,7 @@ export function renderClassifierPage(): string {
|
|
|
22
23
|
return `---
|
|
23
24
|
title: "Planning ClickHouse Changes"
|
|
24
25
|
label: "Planning and the Change Classifier"
|
|
25
|
-
description: "How a ClickHouse schema change is classified as metadata only, a background rewrite or a rebuild, each with the ALTER restriction behind it"
|
|
26
|
+
description: "How a ClickHouse schema change is classified as metadata only, a background rewrite, a replacement or a rebuild, each with the ALTER restriction behind it"
|
|
26
27
|
diataxis: reference
|
|
27
28
|
group: "ClickHouse"
|
|
28
29
|
order: 1
|
|
@@ -36,9 +37,10 @@ Every change between two ClickHouse schemas is classified before anything runs:
|
|
|
36
37
|
|---|---|
|
|
37
38
|
| metadata only | the server records the change and touches no existing data |
|
|
38
39
|
| background rewrite | a mutation rewrites existing parts in the background, with no rollback |
|
|
40
|
+
| replace table | ClickHouse cannot alter a stream-engine table, and it stores no rows, so the applier drops and creates it around the views that read it |
|
|
39
41
|
| rebuild | ClickHouse cannot make the change to the existing table, and the data has to be copied into a new one; a plan refuses to make it in place |
|
|
40
42
|
|
|
41
|
-
Two commands report the classification, and \`chant lifecycle plan\` reports it as each update's disruption (metadata only is \`in-place\`, a rewrite \`rolling\`, a rebuild \`replace\`):
|
|
43
|
+
Two commands report the classification, and \`chant lifecycle plan\` reports it as each update's disruption (metadata only is \`in-place\`, a rewrite \`rolling\`, a replacement or a rebuild \`replace\`):
|
|
42
44
|
|
|
43
45
|
\`\`\`bash
|
|
44
46
|
chant sql diff base.json head.json # two chant build outputs, offline
|
|
@@ -47,13 +49,28 @@ chant sql plan prod schema.json # a build output against the prod server
|
|
|
47
49
|
|
|
48
50
|
Both exit 2 when a change needs a rebuild. \`chant sql diff\` compares a pull request's base and head builds with no server. \`chant sql plan\` reads the server \`sql.profiles.<env>\` binds, and asks that server's formatter about any expression the normalization rules leave different, so the server's own rewriting (\`INTERVAL 1 DAY\` as \`toIntervalDay(1)\`, \`a+b*2\` as \`a + (b * 2)\`) is not reported as a change.
|
|
49
51
|
|
|
50
|
-
\`chant sql plan\` also exits 2 when a declared database holds an object whose definition it cannot read. It names each one under \`Refused\` (\`unreadable\` in \`--json\`) instead of leaving it out. Dictionaries are read and planned like the other objects: any change but a comment replaces one (SQLCH245).
|
|
52
|
+
\`chant sql plan\` also exits 2 when a declared database holds an object whose definition it cannot read. It names each one under \`Refused\` (\`unreadable\` in \`--json\`) instead of leaving it out. It exits 2 as well when the build names a named collection the server doesn't have, naming each under \`Refused\` (\`namedCollections.missing\` in \`--json\`); see [Named collections](../clickhouse-ddl/#named-collections). Dictionaries are read and planned like the other objects: any change but a comment replaces one (SQLCH245).
|
|
51
53
|
|
|
52
54
|
A clause chant's parser does not know ([Plain .sql Files](../sql-files/#clauses-chant-does-not-read)) is compared as text, and the rest of its object is planned as usual. A change to one is SQLCH290, refused for review with no rebuild Op suggested, since chant cannot tell what the change takes. A clause only the server prints is a hint, not a change: a newer server printing a clause with its default looks the same as a clause removed from the declaration.
|
|
53
55
|
|
|
56
|
+
## Stream tables
|
|
57
|
+
|
|
58
|
+
A table on Kafka, S3Queue, AzureQueue, RabbitMQ, NATS or FileLog stores no rows. It is the consumer that a materialized view reads through, and the position it has reached lives in the broker's committed offsets or in Keeper. There is no \`ALTER\` for its engine arguments, settings or columns, and there is nothing to copy, so a change to one is neither metadata nor a rebuild. It is SQLCH225, in the replace class (\`diffStreamTable\` in \`src/clickhouse/plan/diff.ts\`). The plan refuses nothing for it.
|
|
59
|
+
|
|
60
|
+
The applier makes the change in place, in this order (\`replaceStreamSteps\` in \`src/clickhouse/apply/statements.ts\`): \`DETACH TABLE\` for each materialized view on the server that reads the table, \`DROP TABLE ... SYNC\`, the declared \`CREATE TABLE\`, then \`ATTACH TABLE\` for the same views. The plan names the views in a hint. Messages wait in the broker, and files wait in the bucket, while the views are detached. A change that moves a table to or from a stream engine is still SQLCH223, a rebuild, and \`ClickHouseRebuildOp\` refuses a stream-engine table by name (\`streamRefusal\` in \`src/clickhouse/rebuild/observe.ts\`).
|
|
61
|
+
|
|
62
|
+
Two replacements lose the table's position, and the change carries a note saying so (\`positionWarnings\` in \`src/clickhouse/plan/stream.ts\`):
|
|
63
|
+
|
|
64
|
+
- A different \`kafka_group_name\`, as a setting or as the third engine argument, is a different consumer group. It starts from its own committed offsets, or from the start of the topic when it has none.
|
|
65
|
+
- A different S3Queue \`keeper_path\` is a different record of processed files. Every file already seen is processed again.
|
|
66
|
+
|
|
67
|
+
An apply killed between the detach and the attach leaves the views detached, and a detached view is not in \`system.tables\`. Nothing re-attaches it: run \`ATTACH TABLE\` for each view by hand, then plan again. This has not been run against a server.
|
|
68
|
+
|
|
69
|
+
The \`StreamIngest\` composite declares the stream table, the view and the MergeTree target together: see [Composites](../composites/#streamingest).
|
|
70
|
+
|
|
54
71
|
## After the plan
|
|
55
72
|
|
|
56
|
-
The plan only reports. [\`clickhouseApply\`](../applying/) makes the metadata-only
|
|
73
|
+
The plan only reports. [\`clickhouseApply\`](../applying/) makes the metadata-only, background-rewrite and stream-table changes, and refuses a rebuild the same way the plan does, sending nothing for that object. A rebuild runs as \`ClickHouseRebuildOp\`, a gated migration Op that creates the new table, backfills it, verifies it and swaps it in: see [Rebuilding a Table](../rebuild/). Both commands print the Op declaration to start from for each refused table.
|
|
57
74
|
|
|
58
75
|
\`chant migrate\` plays no part in any of this. It translates a file from one lexicon's format into another's, such as a GitHub Actions workflow into GitLab CI, and does not run schema migrations.
|
|
59
76
|
|
|
@@ -76,6 +93,29 @@ A rebuild is never DDL: it is a step naming \`ClickHouseRebuildOp\`, or for a vi
|
|
|
76
93
|
|
|
77
94
|
\`--topology\` renders the statements for where they will run: \`single\` (the default), \`cluster:<name>\`, \`replicated\` or \`cloud\`. On a cluster every statement carries \`ON CLUSTER\` and a MergeTree-family table becomes \`Replicated*MergeTree\` with its Keeper path; in a \`Replicated\` database the tables are \`Replicated*MergeTree\` with no path and no \`ON CLUSTER\`. \`diffStatements(before, after, { topology })\` takes the same choice; see [Applying to a Server](../applying/#topology).
|
|
78
95
|
|
|
96
|
+
## Migration files on a pull request
|
|
97
|
+
|
|
98
|
+
A workspace member that is a goose, golang-migrate, clickhouse-migrations or Flyway directory (see [Workspace kinds](/chant/reference/workspace-kinds/)) has no declaration to diff. On a pull request, \`chant components pr-plan\` lists each migration file the pull request adds to such a member, and the plan note gives every statement in it the class the rules below give the same change. This is the "check" level of adopting chant beside an existing migration tool: it reads files, applies nothing and contacts no server, so it needs no \`--env\`.
|
|
99
|
+
|
|
100
|
+
The up statements are the ones \`chant sql replay\` would run: goose's \`-- +goose Up\` section, the whole \`.up.sql\` file for golang-migrate, the whole file for clickhouse-migrations, and a Flyway file after placeholder substitution with the values in \`flyway.toml\` or \`flyway.conf\`. A file the base commit already has is not new, whatever the pull request does to it. Undo files are left out.
|
|
101
|
+
|
|
102
|
+
\`\`\`text
|
|
103
|
+
\`db/00002_orders.sql\` (member \`ledger\`, postgres)
|
|
104
|
+
- 1. \`CREATE INDEX orders_status_idx ON orders (status)\`: needs CONCURRENTLY (SQLPG241, SHARE)
|
|
105
|
+
- 2. \`ALTER TABLE orders ALTER COLUMN a TYPE bigint\`: undecided between SQLPG206 metadata only and SQLPG207 ACCESS EXCLUSIVE rewrite or scan
|
|
106
|
+
\`\`\`
|
|
107
|
+
|
|
108
|
+
Each statement is read with the dialect's parser (\`CREATE\`, \`GRANT\`, \`COMMENT ON\`) or word by word (\`ALTER\`, \`DROP\`, \`RENAME\`), and the lock on a Postgres statement is the one its rule's text names. The code is \`lexicons/sql/src/postgres/plan/statements.ts\` and \`lexicons/sql/src/clickhouse/plan/statements.ts\`.
|
|
109
|
+
|
|
110
|
+
A statement alone cannot always decide a rule, and then the note names the candidates and does not guess:
|
|
111
|
+
|
|
112
|
+
- \`ALTER COLUMN ... TYPE\` is SQLPG206 or SQLPG207 by the column's old type, and SQLPG208 as well with a \`USING\` expression.
|
|
113
|
+
- \`MODIFY COLUMN <type>\` is SQLCH210 or SQLCH211, \`DROP COLUMN\` SQLCH202 or SQLCH213, and \`RENAME COLUMN\` SQLCH212 or SQLCH213, by whether the column is in a key. When the same file creates the table, its keys are known and the statement is classified.
|
|
114
|
+
- \`MODIFY ORDER BY\` is SQLCH220, a rebuild. It is SQLCH216 or SQLCH220 when the same \`ALTER\` adds the columns the new key ends with, unless the file created the table and shows the old key is kept.
|
|
115
|
+
- \`CREATE OR REPLACE VIEW\` is SQLPG250 or SQLPG251 by whether the view keeps its columns.
|
|
116
|
+
|
|
117
|
+
A statement that reads or writes rows (\`INSERT\`, \`UPDATE\`, \`TRUNCATE\`) is listed as data. A schema change no rule covers, such as \`ALTER TABLE ... OWNER TO\` or a ClickHouse \`DROP PARTITION\`, is listed as having no class.
|
|
118
|
+
|
|
79
119
|
## Identity and renames
|
|
80
120
|
|
|
81
121
|
An object is identified by its export name between two builds, so a changed name in the SQL under the same export is a rename. Against a server, which has no export names, an object is identified by \`database.name\`; a declaration renamed since the server last saw it says so with \`-- previously: <old name>\` before its CREATE.
|
|
@@ -269,6 +269,9 @@ export function renderClickHouseModule(catalog: ClickHouseCatalog): RenderedModu
|
|
|
269
269
|
`/** The table functions (\`system.table_functions\`): \`numbers\`, \`remote\`, \`s3\`. */`,
|
|
270
270
|
`export const TABLE_FUNCTIONS: readonly string[] = ${JSON.stringify(catalog.tableFunctions)};`,
|
|
271
271
|
"",
|
|
272
|
+
`/** The input and output formats (\`system.formats\`): \`Parquet\`, \`JSONEachRow\`. */`,
|
|
273
|
+
`export const FORMATS: readonly string[] = ${JSON.stringify(catalog.formats.map((f) => f.name))};`,
|
|
274
|
+
"",
|
|
272
275
|
`export const SKIP_INDEX_TYPES: Readonly<Record<SkipIndexType, SkipIndexSpec>> = {`,
|
|
273
276
|
...indexLines,
|
|
274
277
|
"};",
|
|
@@ -9,7 +9,7 @@ import type { SqlDialect } from "../dialects";
|
|
|
9
9
|
|
|
10
10
|
const cell = (s: string) => s.replace(/\|/g, "\\|").replace(/[{}<>]/g, (c) => `\\${c}`);
|
|
11
11
|
|
|
12
|
-
const STATUS: Record<KindRow["status"], string> = { declared: "declared", refused: "refused", "out-of-scope": "out of scope" };
|
|
12
|
+
const STATUS: Record<KindRow["status"], string> = { declared: "declared", referenced: "referenced", refused: "refused", "out-of-scope": "out of scope" };
|
|
13
13
|
|
|
14
14
|
function table(dialect: SqlDialect): string {
|
|
15
15
|
const rows = [...KIND_COVERAGE[dialect]].sort((a, b) => (a.command < b.command ? -1 : a.command > b.command ? 1 : 0));
|
|
@@ -27,7 +27,8 @@ function table(dialect: SqlDialect): string {
|
|
|
27
27
|
function counts(dialect: SqlDialect): string {
|
|
28
28
|
const rows = KIND_COVERAGE[dialect];
|
|
29
29
|
const n = (s: KindRow["status"]) => rows.filter((r) => r.status === s).length;
|
|
30
|
-
|
|
30
|
+
const referenced = n("referenced") > 0 ? `, ${n("referenced")} referenced` : "";
|
|
31
|
+
return `${n("declared")} declared${referenced}, ${n("refused")} refused, ${n("out-of-scope")} out of scope`;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export function renderCoveragePage(): string {
|
|
@@ -36,7 +37,7 @@ export function renderCoveragePage(): string {
|
|
|
36
37
|
return `---
|
|
37
38
|
title: "Object Coverage"
|
|
38
39
|
label: "Object Coverage"
|
|
39
|
-
description: "Every kind of object each pinned Postgres and ClickHouse server can create, marked declared, refused with a reason, or out of scope, and what import does with each"
|
|
40
|
+
description: "Every kind of object each pinned Postgres and ClickHouse server can create, marked declared, referenced, refused with a reason, or out of scope, and what import does with each"
|
|
40
41
|
diataxis: reference
|
|
41
42
|
order: 3
|
|
42
43
|
---
|
|
@@ -46,6 +47,7 @@ order: 3
|
|
|
46
47
|
Each row is a \`CREATE\` command a pinned server has, or one form of a command where chant treats the forms apart (\`CREATE TYPE ... AS ENUM\` is declared, \`CREATE TYPE ... AS RANGE\` is not). The commands come from the servers' own sources at each pinned version (\`scripts/sql-create-commands.ts\`), and a test fails when a pinned server has a command with no row here, so a new server release cannot add a kind nobody looked at.
|
|
47
48
|
|
|
48
49
|
- **declared**: a tag declares it, and import writes it as that declaration.
|
|
50
|
+
- **referenced**: the environment's, and never declared: a declaration names one, and chant never reads its values. A ClickHouse named collection is one ([#4395](https://github.com/INTENTIUS/chant/issues/4395)): \`ENGINE = S3(lake_creds, format = 'Parquet')\` names \`lake_creds\`, the build records the name, and \`chant sql plan\` fails when the server has no collection of that name. \`chant import --from <env>\` lists the server's SQL-defined collections as prerequisites and imports the rest. See [Named collections](../clickhouse-ddl/#named-collections).
|
|
49
51
|
- **refused**: no declaration holds it yet. \`chant import --from <env>\` fails when the server has one, naming every such object (kind, schema, name) at once, and \`chant import schema.sql\` fails on the statement. Nothing is left out without a word.
|
|
50
52
|
- **out of scope**: the environment's, not a schema's: import never reads it.
|
|
51
53
|
|
package/src/codegen/docs.ts
CHANGED
|
@@ -122,7 +122,7 @@ Postgres:
|
|
|
122
122
|
- [Getting Started with Postgres](./postgres-getting-started/): declare a
|
|
123
123
|
schema, apply it to a local server, add a column and an index, and see a
|
|
124
124
|
rename refused.
|
|
125
|
-
- [Declaring Postgres Objects](./postgres-ddl/): the
|
|
125
|
+
- [Declaring Postgres Objects](./postgres-ddl/): the tags for every schema-level kind,
|
|
126
126
|
constraints, \`nextval(\${seq})\`, \`COMMENT ON\` and \`literal()\`.
|
|
127
127
|
- [Importing a Postgres Server](./postgres-importing/): canonical text from
|
|
128
128
|
the catalog's printers, and the objects that belong to someone else.
|
|
@@ -65,14 +65,14 @@ A column rename or a type change across kinds is never DDL: it is a step naming
|
|
|
65
65
|
|
|
66
66
|
## Which major
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
Three rules change class across the supported majors: a STORED generated column's expression (SQLPG212) is a rewrite from 17 and expand and contract before it, a table's access method (SQLPG226) is a rewrite from 15 and expand and contract before it, and an operator's commutator, negator, HASHES and MERGES (SQLPG304) are altered in place from 17 and dropped and created before it.
|
|
69
69
|
|
|
70
70
|
- \`chant sql diff\` classifies for the major the builds recorded (\`postgresMajor\` in the build output): the newer build's, else the older build's, else \`sql.postgresMajor\`, else 18. A diff between two revisions does not depend on today's config.
|
|
71
71
|
- \`chant sql plan\` classifies for the major the server runs (\`server_version_num\`), since the server is what takes the locks. When the build targets another major, the plan says so in a hint.
|
|
72
72
|
|
|
73
73
|
## Identity and renames
|
|
74
74
|
|
|
75
|
-
An object is identified by its export name between two builds, and by its schema-qualified name against a server, which has no export names. Tables, views, materialized views, sequences and indexes share one namespace per schema, types and domains another, and schemas and extensions are matched by name. Functions, procedures and aggregates share a namespace of their own and are told apart by their input parameter types, so an overload is another object; composite and range types share the types' namespace, collations have one of their own,
|
|
75
|
+
An object is identified by its export name between two builds, and by its schema-qualified name against a server, which has no export names. Tables, foreign tables, views, materialized views, sequences and indexes share one namespace per schema, types and domains another, and schemas and extensions are matched by name. Functions, procedures and aggregates share a namespace of their own and are told apart by their input parameter types, so an overload is another object; composite and range types share the types' namespace, collations have one of their own, extended statistics another, an operator by its symbol and operand types, an operator class and an operator family each by its name and index method, text search configurations one namespace and dictionaries another, a cast by its two types and an event trigger, a foreign data wrapper, a foreign server and a publication by their names in the database; a trigger is matched by its name on its table.
|
|
76
76
|
|
|
77
77
|
A rename is declared where it happens. Before a CREATE, \`-- previously: <old name>\` says the object had another name; on a column's line, it says the column did:
|
|
78
78
|
|