Skip to content

Manage SystemDB schema via Liquibase, not Hibernate hbm2ddl#6003

Open
delchev wants to merge 3 commits into
masterfrom
db-sys-liquibase
Open

Manage SystemDB schema via Liquibase, not Hibernate hbm2ddl#6003
delchev wants to merge 3 commits into
masterfrom
db-sys-liquibase

Conversation

@delchev

@delchev delchev commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • New components/core/core-liquibase module owns the DIRIGIBLE_* schema for SystemDB via a Liquibase JSON changelog (db/changelog/dirigible-system.json, 131 changesets, 52 tables).
  • DIRIGIBLE_DATABASE_SYSTEM_DDL_AUTO default flipped from updatenone. Hibernate on SystemDB now issues no DDL and no schema probes at boot, eliminating the H2 SYS-lock race that multiple Spring test contexts triggered during DDL planning.
  • DataSourceSystemConfig.entityManagerFactory gains @DependsOn("liquibaseSystemDB") so the changelog runs before Hibernate wires up.
  • LegacyAwareSpringLiquibase detects existing deployments (DIRIGIBLE_SECURITY_ACCESS exists, no DATABASECHANGELOG) and calls changeLogSync() so every changeset is marked applied without re-running DDL — zero data loss on upgrade.

Scope

  • SystemDB cutover only. Dynamic user entities (TypeScript @Entity via data-store, Java @Entity via data-store-java) are untouched and keep hbm2ddl=update — their schema is authored by user code, not by versioned changelogs.

Source of the changelog

Baseline generated by running liquibase generate-changelog against a fresh hbm2ddl-built H2 SystemDB, then post-processed to:

  • Replace H2-auto constraint names (CONSTRAINT_18, CONSTRAINT_CB, ...) with deterministic ones (PK_<table>, UK_<table>_<col>, FK_<base>__<col>, IX_<table>_<col>).
  • Map VARCHAR(1000000000) (Hibernate's unbounded String) to:
    • VARCHAR(2000) for columns that participate in any PK/UK/FK/index (H2 can't index CLOB).
    • CLOB for non-indexed content columns (BPMN_CONTENT, CAMEL_CONTENT, etc.) — Liquibase translates CLOB to the right vendor type (H2 CLOB, Postgres TEXT, MSSQL NVARCHAR(MAX)).
  • Map H2 ENUM(...) to VARCHAR(50) for portability across Postgres/MSSQL.
  • Assign stable descriptive changeset ids (create-DIRIGIBLE_<table>, UK_<table>_<col>, ...) so future regeneration doesn't churn history.

Test plan

  • Local: mvn -pl tests/tests-integrations -P integration-tests -Dit.test=JavaEngineIT verify → all 4 tests pass on a fresh H2 in 103s.
  • CI: integration-tests-h2, -postgresql, -mssql on this PR — the multi-vendor matrix exercises Liquibase's type translation. Possible follow-ups if vendor-specific tweaks are needed.
  • Manual verification of the legacy upgrade path: deploy on a SystemDB that has all DIRIGIBLE_* tables but no DATABASECHANGELOG, then start the app — LegacyAwareSpringLiquibase.isLegacyDeployment() should log Legacy deployment detected — ... marking every changeset as applied via changelogSync() and the existing rows survive.

🤖 Generated with Claude Code

delchev and others added 3 commits June 10, 2026 12:21
The DIRIGIBLE_* platform tables in SystemDB are now created by Liquibase
changelogs in a new core-liquibase module (db/changelog/dirigible-system.json,
131 changesets covering 52 tables). Hibernate's hbm2ddl on SystemDB is set
to "none" by default — it does no DDL and no schema probes at boot. That
eliminates the SYS-lock race we saw on master where multiple Spring contexts
in the same JVM raced through H2's DDL-planning phase.

DataSourceSystemConfig's entityManagerFactory gains @dependsOn("liquibaseSystemDB")
so Liquibase runs before Hibernate wires up. LegacyAwareSpringLiquibase
detects existing deployments (DIRIGIBLE_SECURITY_ACCESS exists, but no
DATABASECHANGELOG) and calls changeLogSync() to mark every changeset
applied without re-running DDL — zero data loss on upgrade.

Dynamic user entities (TypeScript @entity via data-store, Java @entity via
data-store-java) are unchanged — they keep hbm2ddl=update because their
schema is authored by user code, not by versioned changelogs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous commit broke every JPA-using module's unit tests in two ways:

(1) @dependsOn("liquibaseSystemDB") on the SystemDB EntityManagerFactory
made the Liquibase bean a *required* dependency. Unit tests that boot a
slim Spring context (engine-javascript's JavascriptEndpointTest etc.)
don't pull in core-liquibase, so the bean is missing and the context
fails with "depends on missing bean 'liquibaseSystemDB'".

Fix: move the dependency declaration into core-liquibase via a
LiquibaseEntityManagerFactoryDependsOnPostProcessor (extending Spring
Boot's own EntityManagerFactoryDependsOnPostProcessor — same pattern
Spring Boot's LiquibaseAutoConfiguration uses). When core-liquibase is
on the classpath the BFPP runs and adds the dependsOn; when it's not
(slim unit tests), no BFPP, no dependency, EMF wires normally.

(2) Flipping hbm2ddl from "update" to "none" broke every unit test that
boots its own slim JPA context — e.g. data-sources' DataSourceRepositoryTest
expects Hibernate to bootstrap DIRIGIBLE_DATA_SOURCES because it doesn't
have Liquibase on its classpath.

Fix: restore "update" as the default. In the full app, Liquibase runs
first (BFPP ordering) and creates every table, so Hibernate's update pass
sees a populated schema and emits zero DDL — the SYS-lock race that motivated
the change is killed regardless, because the race was CREATE TABLEs racing,
not the existence probe. In unit tests without Liquibase, Hibernate creates
the schema as it always did. Operators who specifically want validate or
none after adopting Liquibase set DIRIGIBLE_DATABASE_SYSTEM_DDL_AUTO.

Verified locally with the full `mvn -P unit-tests clean install` and
JavaEngineIT.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CLAUDE.md inside core-liquibase covering the architecture (BFPP + Spring
Liquibase + LegacyAwareSpringLiquibase), the changelog conventions, and
— most importantly — the mandatory checklist for anyone touching a JPA
@entity in SystemDB: every new entity, column, or constraint owes an
appended changeset in db/changelog/dirigible-system.json. Hibernate's
hbm2ddl=update masks the omission in local development; production
deployments running with hbm2ddl=validate would surface it as an outage.

Also captures the portability gotchas that bit us during the baseline
authoring (CLOB cannot be indexed on H2 → VARCHAR(2000) for indexed
unbounded columns; ENUM is H2-only → use VARCHAR(50)), and the
legacy-deployment changelogSync path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant