Skip to content

fix: inline primary keys in liquibase changelog for MySQL GIPK support - #1508

Open
fudianchn wants to merge 2 commits into
quartz-scheduler:mainfrom
fudianchn:fix/liquibase-gipk-primary-key-1489
Open

fix: inline primary keys in liquibase changelog for MySQL GIPK support#1508
fudianchn wants to merge 2 commits into
quartz-scheduler:mainfrom
fudianchn:fix/liquibase-gipk-primary-key-1489

Conversation

@fudianchn

@fudianchn fudianchn commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

AI disclosure: this change was prepared with AI coding agents, reviewed and revised line by line by me.

What

Inline the composite primary keys into the <createTable> definitions in liquibase.quartz.init.xml (and drop the now-redundant <addPrimaryKey> changes), so the changelog runs successfully on MySQL 8.0.30+ with sql_generate_invisible_primary_key=ON.

Why

MySQL 8.0.30+ can generate an invisible primary key (my_row_id) for any InnoDB table created without an explicit PK when sql_generate_invisible_primary_key=ON. This setting is on by default and cannot be disabled via SQL on Azure MySQL Flexible Server. With GIPK on, the current changelog fails on the first table:

ChangeSet liquibase/liquibase.quartz.init.xml::quartz-init::quartz encountered an exception.
liquibase.exception.DatabaseException: Multiple primary key defined
[Failed SQL: (1068) ALTER TABLE QRTZ_LOCKS ADD PRIMARY KEY (SCHED_NAME, LOCK_NAME)]

Each table is created without an inline PK (so MySQL injects the invisible one), then the separate <addPrimaryKey> tries to add another PK → Multiple primary key defined (1068), aborting the whole changeset. Closes #1489.

Root cause

<createTable> with no PK → GIPK auto-creates an invisible PK → the subsequent <addPrimaryKey> collides with it (error 1068).

How

For each of the 11 tables, mark the primary-key columns with <constraints nullable="false" primaryKey="true"/> inside <createTable> and remove the separate <addPrimaryKey> change. Liquibase then emits a single composite PRIMARY KEY (...) inside the CREATE TABLE, so MySQL sees the explicit PK at creation time and GIPK does not fire. The PK columns are the leading columns of every table (original order preserved), so the resulting schema is identical for non-GIPK databases.

Testing

End-to-end against MySQL 8.0 (Docker, sql_generate_invisible_primary_key=ON) via liquibase update (Liquibase 4.29.2):

Before (main): the changeset aborts with exactly the reported error — only QRTZ_LOCKS is created before the failure:

ChangeSet quartz-init::quartz encountered an exception.
liquibase.exception.DatabaseException: Multiple primary key defined
[Failed SQL: (1068) ALTER TABLE QRTZ_LOCKS ADD PRIMARY KEY (SCHED_NAME, LOCK_NAME)]

After (this PR): all 11 tables are created with the intended composite PKs and no generated invisible column, e.g.:

SHOW CREATE TABLE QRTZ_LOCKS →  PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)   -- no `my_row_id` invisible column

liquibase updateSQL confirms the SQL change: main emits 11 ALTER TABLE ... ADD PRIMARY KEY statements; this PR emits 0 (PKs are inline in CREATE TABLE).

Note on existing installations (would appreciate the maintainer's call)

This modifies the existing monolithic quartz-init changeset, so its Liquibase checksum changes. Databases that already ran the previous version (necessarily non-GIPK ones, since it cannot run under GIPK) will report a checksum mismatch on the next liquibase update. Options:

  1. Document liquibase clearCheckSums for upgraders (what this PR currently assumes).
  2. Add <validCheckSum>9:f3cf9344fdd4a3f171a42f112ce3d5f0</validCheckSum> for the prior checksum (computed with Liquibase 4.29.2) so existing runs validate — note checksums are Liquibase-version-specific.
  3. Split into a new changeset id.

I went with the inline-PK change as the minimal, schema-identical fix and left the changeset id unchanged. Happy to add <validCheckSum> or restructure the changeset if a different approach is preferred.

Fixes #1489

MySQL 8.0.30+ with sql_generate_invisible_primary_key=ON (the default
on Azure MySQL Flexible Server, and not disable-able via SQL there)
auto-generates an invisible primary key for any InnoDB table created
without an explicit primary key. The liquibase changelog created each
table without an inline PK and then added the PK via a separate
<addPrimaryKey> change, so the second statement failed with
"Multiple primary key defined" (1068) and the whole changeset aborted.

Move the composite primary keys into the <createTable> definitions
(mark the PK columns with primaryKey="true") and drop the now-redundant
<addPrimaryKey> changes. The resulting schema is identical for databases
without GIPK; on GIPK-enabled databases the PK is declared up front, so
MySQL no longer injects an invisible one.

Verified end-to-end against MySQL 8.0 with GIPK enabled:
- before: `liquibase update` aborts with "Multiple primary key defined
  [Failed SQL: (1068) ALTER TABLE QRTZ_LOCKS ADD PRIMARY KEY ...]" (only
  QRTZ_LOCKS is created before the failure)
- after: all 11 tables created with the intended composite PKs and no
  generated my_row_id invisible column.

Note: this modifies the existing monolithic `quartz-init` changeset, so
its checksum changes. Databases that already ran the previous version
will report a checksum mismatch on the next `liquibase update` and need
`liquibase clearCheckSums`; see the PR for alternatives
(<validCheckSum> / splitting the changeset).

Fixes quartz-scheduler#1489

Signed-off-by: 付典 <fudianchn@gmail.com>
Add a JDK XML-parser based test that asserts liquibase.quartz.init.xml
declares every primary key inline in <createTable> and contains no
standalone <addPrimaryKey>. A separate <addPrimaryKey> is exactly what
collides with the invisible primary key MySQL 8.0.30+ auto-generates
under sql_generate_invisible_primary_key=ON (issue quartz-scheduler#1489), so this
locks the inline-PK structure in as a regression guard.

Uses only the JDK XML parser, so it introduces no new dependencies. It
fails against the pre-fix changelog (11 <addPrimaryKey> changes) and
passes against the inlined version.

Signed-off-by: 付典 <fudianchn@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

is:bug Bugs to fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MySQL 8.0.30+: liquibase.quartz.init.xml fails if sql_generate_invisible_primary_key is enabled

2 participants