From ee631babc72790c5fd0005016ff71499aea35eca Mon Sep 17 00:00:00 2001 From: xaviermarchegay Date: Tue, 20 Oct 2026 17:00:47 +0200 Subject: [PATCH 1/2] #185 - Version20261005120000: drop and create again the log_record foreign key around the NOT NULL change Without a strict SQL mode, MySQL makes the column NOT NULL with ALGORITHM=COPY, which is refused on a foreign key column (error 1832). Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + src/Migrations/Version20261005120000.php | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a998b2d..5cf857d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Latest * [#150](https://github.com/cleverage/ui-process-bundle/issues/150) Require `symfony/monolog-bundle` and `monolog/monolog`, used directly by the bundle (log handlers, `monolog` configuration prepended, `monolog.logger` tags) but only installed through `cleverage/process-bundle`, which may stop requiring MonologBundle (cleverage/process-bundle#269). ## Fixes +* [#185](https://github.com/cleverage/ui-process-bundle/issues/185) `Version20261005120000` migration (#97), MySQL / MariaDB: the `log_record.process_execution_id` foreign key is dropped and created again around the change to `NOT NULL`. Without a strict SQL mode (neither `STRICT_TRANS_TABLES` nor `STRICT_ALL_TABLES`), MySQL makes the column `NOT NULL` with `ALGORITHM=COPY`, which is refused on a foreign key column: the migration failed with "1832 Cannot change column 'process_execution_id': used in a foreign key constraint 'FK_8ECECC333DAC0075'". Same resulting schema. * [#174](https://github.com/cleverage/ui-process-bundle/issues/174) Long-running workers (Messenger, scheduler): `ProcessExecutionManager` implements `ResetInterface` (`kernel.reset` tag), its current and last process executions are reset between two messages; `DoctrineProcessHandler` drops the log records not written at the end of the previous execution on `reset()` (`kernel.reset` tag). `ProcessEventSubscriber` forgets the ended process execution (and closes its log file) even when it cannot be saved: the next process executed by the worker was attached to it. Add tests. * [#173](https://github.com/cleverage/ui-process-bundle/issues/173) Fix the hard-coded URLs: the page displayed after the login is generated from the dashboard route (was `/process`: wrong when the routes are imported with a `prefix`, or the application is served from a sub-directory), and the logo URL is built by the Asset component (base path, `framework.assets.base_urls`, version strategy; absolute URLs kept as is; was `/`). New `ProcessDashboardController` constructor argument (`Symfony\Component\Asset\Packages`, autowired). Require `symfony/asset`, used directly. Add tests. * [#171](https://github.com/cleverage/ui-process-bundle/issues/171) Configuration: `config:dump-reference clever_age_ui_process` and `debug:config clever_age_ui_process` no longer fail (`CleverAgeUiProcessExtension::getConfiguration()` gives the kernel environment to `Configuration`, so the PHP config builder is generated too); the options are documented with `info()`. The `logs.database_level`, `logs.file_level` and `logs.report_increment_level` options are validated when the container is compiled, an invalid level no longer makes every process execution fail at runtime (environment variables are still allowed, checked at runtime). Update documentation, add tests. diff --git a/src/Migrations/Version20261005120000.php b/src/Migrations/Version20261005120000.php index 6bb831a..73d26a5 100644 --- a/src/Migrations/Version20261005120000.php +++ b/src/Migrations/Version20261005120000.php @@ -41,9 +41,15 @@ public function up(Schema $schema): void // Log records without process execution are never displayed (the UI lists the logs of an execution) $this->addSql('DELETE FROM log_record WHERE process_execution_id IS NULL'); - $this->addSql($mySql - ? 'ALTER TABLE log_record MODIFY process_execution_id INT NOT NULL' - : 'ALTER TABLE log_record ALTER process_execution_id SET NOT NULL'); + if ($mySql) { + // Without a strict SQL mode, MySQL makes the column NOT NULL with ALGORITHM=COPY, which is refused on a + // foreign key column (error 1832): the foreign key is dropped and created again around the change + $this->addSql('ALTER TABLE log_record DROP FOREIGN KEY FK_8ECECC333DAC0075'); + $this->addSql('ALTER TABLE log_record MODIFY process_execution_id INT NOT NULL'); + $this->addSql('ALTER TABLE log_record ADD CONSTRAINT FK_8ECECC333DAC0075 FOREIGN KEY (process_execution_id) REFERENCES process_execution (id) ON DELETE CASCADE'); + } else { + $this->addSql('ALTER TABLE log_record ALTER process_execution_id SET NOT NULL'); + } $this->addSql($mySql ? 'ALTER TABLE process_execution MODIFY context JSON DEFAULT NULL' : 'ALTER TABLE process_execution ALTER context DROP NOT NULL'); From 4d75e0ec7e5489c88eb4f6d11678b75209fadc6b Mon Sep 17 00:00:00 2001 From: xaviermarchegay Date: Tue, 20 Oct 2026 17:46:16 +0200 Subject: [PATCH 2/2] #185 - Version20261005120000: disable foreign_key_checks around the NOT NULL change instead of dropping the foreign key Dropping and adding the foreign key back copies the whole log_record table and blocks writes, also in strict mode. foreign_key_checks = 0 keeps the foreign key and its in-place change. CI: run the migrations on MySQL without a strict SQL mode too. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/test.yml | 17 ++++++++++++++++- CHANGELOG.md | 2 +- src/Migrations/Version20261005120000.php | 7 ++++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 88cd07b..4572279 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -111,7 +111,7 @@ jobs: # files: build/logs/clover.xml migrations: - name: Migrations ${{ matrix.database }} + DBAL ${{ matrix.dbal }} + name: Migrations ${{ matrix.database }} + DBAL ${{ matrix.dbal }}${{ matrix.sql-mode == 'non-strict' && ' (non-strict SQL mode)' || '' }} runs-on: ubuntu-latest env: SYMFONY_REQUIRE: ${{ matrix.symfony-require }} @@ -122,6 +122,7 @@ jobs: matrix: database: [mysql, mariadb, postgresql] dbal: ['3', '4'] + sql-mode: [strict] include: - database: mysql image: mysql:8.4 @@ -144,6 +145,17 @@ jobs: - dbal: '4' php-version: '8.5' symfony-require: '' + # Without a strict SQL mode, MySQL changes some columns with ALGORITHM=COPY (#185). A new combination, as + # sql-mode is a matrix value: every value is repeated + - database: mysql + dbal: '4' + sql-mode: non-strict + image: mysql:8.4 + port: 3306 + health-cmd: mysqladmin ping -h 127.0.0.1 + database-url: mysql://app:app@127.0.0.1:3306/app?serverVersion=8.4.0 + php-version: '8.5' + symfony-require: '' services: database: @@ -185,6 +197,9 @@ jobs: uses: ramsey/composer-install@v4 with: dependency-versions: highest + - name: Non-strict SQL mode + if: matrix.sql-mode == 'non-strict' + run: mysql -h127.0.0.1 -uroot -proot -e "SET GLOBAL sql_mode = ''" - name: Run the migrations run: tests/App/bin/console doctrine:migrations:migrate --no-interaction # DBAL 3 does not read the PostgreSQL identity columns created by the migrations (it expects sequences): the diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cf857d..2823c9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ Latest * [#150](https://github.com/cleverage/ui-process-bundle/issues/150) Require `symfony/monolog-bundle` and `monolog/monolog`, used directly by the bundle (log handlers, `monolog` configuration prepended, `monolog.logger` tags) but only installed through `cleverage/process-bundle`, which may stop requiring MonologBundle (cleverage/process-bundle#269). ## Fixes -* [#185](https://github.com/cleverage/ui-process-bundle/issues/185) `Version20261005120000` migration (#97), MySQL / MariaDB: the `log_record.process_execution_id` foreign key is dropped and created again around the change to `NOT NULL`. Without a strict SQL mode (neither `STRICT_TRANS_TABLES` nor `STRICT_ALL_TABLES`), MySQL makes the column `NOT NULL` with `ALGORITHM=COPY`, which is refused on a foreign key column: the migration failed with "1832 Cannot change column 'process_execution_id': used in a foreign key constraint 'FK_8ECECC333DAC0075'". Same resulting schema. +* [#185](https://github.com/cleverage/ui-process-bundle/issues/185) `Version20261005120000` migration (#97), MySQL (MariaDB shares the same code): `foreign_key_checks` is disabled around the change of `log_record.process_execution_id` to `NOT NULL`, the foreign key is kept as is. Without a strict SQL mode (neither `STRICT_TRANS_TABLES` nor `STRICT_ALL_TABLES`), MySQL makes the column `NOT NULL` with `ALGORITHM=COPY`, which is refused on a foreign key column while `foreign_key_checks` is enabled: the migration failed with "1832 Cannot change column 'process_execution_id': used in a foreign key constraint 'FK_8ECECC333DAC0075'". Same resulting schema. If the migration failed, run the migrations again after the update; if the workaround of #185 was applied (`doctrine:migrations:version ... --add`), there is nothing to do. CI: the migrations are also run on MySQL without a strict SQL mode. * [#174](https://github.com/cleverage/ui-process-bundle/issues/174) Long-running workers (Messenger, scheduler): `ProcessExecutionManager` implements `ResetInterface` (`kernel.reset` tag), its current and last process executions are reset between two messages; `DoctrineProcessHandler` drops the log records not written at the end of the previous execution on `reset()` (`kernel.reset` tag). `ProcessEventSubscriber` forgets the ended process execution (and closes its log file) even when it cannot be saved: the next process executed by the worker was attached to it. Add tests. * [#173](https://github.com/cleverage/ui-process-bundle/issues/173) Fix the hard-coded URLs: the page displayed after the login is generated from the dashboard route (was `/process`: wrong when the routes are imported with a `prefix`, or the application is served from a sub-directory), and the logo URL is built by the Asset component (base path, `framework.assets.base_urls`, version strategy; absolute URLs kept as is; was `/`). New `ProcessDashboardController` constructor argument (`Symfony\Component\Asset\Packages`, autowired). Require `symfony/asset`, used directly. Add tests. * [#171](https://github.com/cleverage/ui-process-bundle/issues/171) Configuration: `config:dump-reference clever_age_ui_process` and `debug:config clever_age_ui_process` no longer fail (`CleverAgeUiProcessExtension::getConfiguration()` gives the kernel environment to `Configuration`, so the PHP config builder is generated too); the options are documented with `info()`. The `logs.database_level`, `logs.file_level` and `logs.report_increment_level` options are validated when the container is compiled, an invalid level no longer makes every process execution fail at runtime (environment variables are still allowed, checked at runtime). Update documentation, add tests. diff --git a/src/Migrations/Version20261005120000.php b/src/Migrations/Version20261005120000.php index 73d26a5..af7277b 100644 --- a/src/Migrations/Version20261005120000.php +++ b/src/Migrations/Version20261005120000.php @@ -43,10 +43,11 @@ public function up(Schema $schema): void $this->addSql('DELETE FROM log_record WHERE process_execution_id IS NULL'); if ($mySql) { // Without a strict SQL mode, MySQL makes the column NOT NULL with ALGORITHM=COPY, which is refused on a - // foreign key column (error 1832): the foreign key is dropped and created again around the change - $this->addSql('ALTER TABLE log_record DROP FOREIGN KEY FK_8ECECC333DAC0075'); + // foreign key column while foreign_key_checks is enabled (error 1832). The log records without process + // execution are deleted above, the foreign key is kept as is + $this->addSql('SET foreign_key_checks = 0'); $this->addSql('ALTER TABLE log_record MODIFY process_execution_id INT NOT NULL'); - $this->addSql('ALTER TABLE log_record ADD CONSTRAINT FK_8ECECC333DAC0075 FOREIGN KEY (process_execution_id) REFERENCES process_execution (id) ON DELETE CASCADE'); + $this->addSql('SET foreign_key_checks = 1'); } else { $this->addSql('ALTER TABLE log_record ALTER process_execution_id SET NOT NULL'); }