data-structures: a table may carry more than one unique constraint (#7343) - #7356
Open
delchev wants to merge 1 commit into
Open
data-structures: a table may carry more than one unique constraint (#7343)#7356delchev wants to merge 1 commit into
delchev wants to merge 1 commit into
Conversation
…7343) TableConstraint, the @MappedSuperclass behind the unique / foreign-key / check / primary-key constraints, joined its owning TableConstraints with @OnetoOne. The relation is many-to-one - one table's TableConstraints owns a LIST of uniques, a list of foreign keys and a list of checks - and the @OnetoOne made Hibernate put a unique index on the join column, so each of those tables could hold at most one row per table. A table declaring a second unique key therefore failed its second insert with a duplicate key, SchemasSynchronizer failed the whole .schema, and on a fresh instance none of that module's tables were ever created. Nothing in front of it said so: the model, the generated .schema and the publish were all green, and the key the author declared simply constrained nothing. The mapping is @manytoone now. The index it created is already materialized on every deployed instance, so it is dropped by three changesets naming the constraints this changelog created, plus an H2 and a PostgreSQL sweep for a deployment bootstrapped by hbm2ddl before the changelog existed, whose index carries the name Hibernate generated for it. Both sweeps are no-ops where nothing is left, so the changelog stays idempotent. SchemaTwoUniqueConstraintsIT publishes a .schema with two unique keys on one table and asserts both reach the database and each refuses its own duplicate. It fails on master with the reported 23505 and no table created at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cause
TableConstraint- the@MappedSuperclassbehindTableConstraintUnique/…ForeignKey/…Check/…PrimaryKey- joined its owningTableConstraintswith@OneToOne. The relation is genuinely many-to-one: one table'sTableConstraintsowns a list of uniques, a list of foreign keys and a list of checks.@OneToOneon the owning side makes Hibernate put a unique index on the join column, soDIRIGIBLE_DATA_TABLE_UNIQUES.CONSTRAINTS_IDcould hold at most one row per table.A table declaring a second unique key therefore failed its second insert with
23505,SchemasSynchronizerfailed the whole.schema, and on a fresh instance none of that module's tables were ever created. Every step in front of that was green - the model, the generated.schema, the emission audit, the publish - and the declared key simply constrained nothing.The change
TableConstraint.constraintsis@ManyToOne.TableConstraints.primaryKeystays the@OneToOne(mappedBy = "constraints")it is (a table has one primary key); Hibernate maps that inverse side against a@ManyToOneowner without complaint, and its ownUK_DIRIGIBLE_DATA_TABLE_PRIMARYKEYS_CONSTRAINTS_IDis left in place, being correct there.…_UNIQUES,…_FOREIGNKEYSand…_CHECKS, each guarded byuniqueConstraintExists+MARK_RAN. Two more sweep a deployment bootstrapped byhbm2ddlbefore this changelog existed, whose index carries the name Hibernate generated for it and which a drop-by-name cannot reach: one for H2 (EXECUTE IMMEDIATEoverINFORMATION_SCHEMA) and one for PostgreSQL (aDOblock overinformation_schema), both keyed on the column rather than the name and both no-ops where nothing is left, so the changelog stays idempotent (SystemChangelogIdempotencyTestapplies it twice). MSSQL is deliberately not swept - it has no CI leg to verify the statement against, and untested DDL running at every customer's startup is worse than the stated omission.Verification
SchemaTwoUniqueConstraintsIT(new) publishes a.schemawith two unique keys on one table, asserts both reach the database's index catalog, and asserts each one refuses its own duplicate by the name in the refusal message. Run green on H2 and on PostgreSQL (both datasource and SystemDB pointed at a local PostgreSQL, as the CI leg does)..schemamarked failed, and the table not created at all.SchemaTemplateUniqueConstraintIT,SchemaTemplateForeignKeyIT,SchemaClobColumnIT,SchemaRepublishTypeToleranceIT,IntentCrossModelUniqueIT,EdmUniqueKeyRoundTripIT- green.data-structures,core-liquibaseandbuild/application(which carriesSystemSchemaChangelogCoverageTest) - green.mvn formatter:validatewith the cache wiped, and therelease-profile javadoc build ondata-structures- green.Not verified: MSSQL (no CI leg), and the legacy sweeps were exercised as raw SQL against H2 and PostgreSQL rather than against a genuinely pre-changelog database.
Fixes #7343
🤖 Generated with Claude Code