diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index bf419069870..eb5783e6507 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -349,10 +349,11 @@ jobs:
strategy:
matrix:
php-version:
- - "8.1"
+ - "8.3"
mysql-version:
- "5.7"
- "8.0"
+ - "9.0"
extension:
- "mysqli"
- "pdo_mysql"
@@ -363,18 +364,19 @@ jobs:
php-version: "8.1"
mysql-version: "8.0"
extension: "mysqli"
- - php-version: "8.2"
+ - php-version: "8.1"
mysql-version: "8.0"
extension: "mysqli"
- - php-version: "8.3"
+ - php-version: "8.1"
mysql-version: "8.0"
extension: "pdo_mysql"
- - php-version: "8.1"
+ # Workaround for https://bugs.mysql.com/114876
+ - php-version: "8.3"
mysql-version: "8.4"
extension: "mysqli"
custom-entrypoint: >-
--entrypoint sh mysql:8.4 -c "exec docker-entrypoint.sh mysqld --mysql-native-password=ON"
- - php-version: "8.1"
+ - php-version: "8.3"
mysql-version: "8.4"
extension: "pdo_mysql"
custom-entrypoint: >-
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
new file mode 100644
index 00000000000..92841c15734
--- /dev/null
+++ b/.github/workflows/nightly.yml
@@ -0,0 +1,72 @@
+name: "Continuous Integration (Nightly)"
+
+on:
+ schedule:
+ - cron: "12 3 * * *"
+ workflow_dispatch:
+
+env:
+ fail-fast: true
+
+jobs:
+ phpunit-mariadb:
+ name: "PHPUnit with MariaDB"
+ runs-on: "ubuntu-24.04"
+
+ strategy:
+ matrix:
+ php-version:
+ - "8.3"
+ mariadb-version:
+ - "earliest"
+ - "verylatest"
+ extension:
+ - "mysqli"
+ - "pdo_mysql"
+
+ services:
+ mariadb:
+ image: "quay.io/mariadb-foundation/mariadb-devel:${{ matrix.mariadb-version }}"
+ env:
+ MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: yes
+ MARIADB_DATABASE: "doctrine_tests"
+
+ options: >-
+ --health-cmd "healthcheck.sh --connect --innodb_initialized"
+
+ ports:
+ - "3306:3306"
+
+ steps:
+ - name: "Checkout"
+ uses: "actions/checkout@v4"
+ with:
+ fetch-depth: 2
+
+ - name: "Install PHP"
+ uses: "shivammathur/setup-php@v2"
+ with:
+ php-version: "${{ matrix.php-version }}"
+ coverage: "pcov"
+ ini-values: "zend.assertions=1"
+ extensions: "${{ matrix.extension }}"
+
+ - name: "Install dependencies with Composer"
+ uses: "ramsey/composer-install@v3"
+ with:
+ composer-options: "--ignore-platform-req=php+"
+
+ - name: "Run PHPUnit"
+ run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml"
+
+ - name: Tell the MariaDB Folks if it failed
+ if: ${{ failure() }}
+ uses: zulip/github-actions-zulip/send-message@v1
+ with:
+ api-key: ${{ secrets.MARIADB_ZULIP_API_KEY }}
+ email: "doctrine-bot@mariadb.zulipchat.com"
+ organization-url: "https://mariadb.zulipchat.com"
+ to: "Buildbot"
+ type: "stream"
+ topic: "CI - Doctrine/DBAL"
+ content: "There was an error running Doctrine on MariaDB:${{ matrix.mariadb-version }} - URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}."
diff --git a/docs/en/reference/platforms.rst b/docs/en/reference/platforms.rst
index 97412a461b2..11efd997d73 100644
--- a/docs/en/reference/platforms.rst
+++ b/docs/en/reference/platforms.rst
@@ -76,20 +76,34 @@ database vendor and version best. Otherwise it is not guaranteed
that the compatibility in terms of SQL dialect and feature support
between Doctrine DBAL and the database server will always be given.
-If you want to overwrite parts of your platform you can do so when
-creating a connection. There is a ``platform`` option you can pass
-an instance of the platform you want the connection to use:
+If you want to overwrite parts of your platform you can do so by
+using a middleware:
::
'pdo_sqlite',
- 'path' => 'database.sqlite',
- 'platform' => $myPlatform,
- ];
- $conn = DriverManager::getConnection($options);
+ class CustomSQLitePlatform extends SqlitePlatform {}
+
+ class CustomDriver extends AbstractDriverMiddleware
+ {
+ public function getDatabasePlatform(ServerVersionProvider $versionProvider)
+ {
+ return new CustomSQLitePlatform();
+ }
+ }
+
+ class CustomMiddleware implements Driver\Middleware
+ {
+ public function wrap(Driver $driver): Driver
+ {
+ return new CustomDriver($driver);
+ }
+ }
+
+ $config = new Doctrine\DBAL\Configuration();
+ $config->setMiddlewares([new CustomMiddleware()]);
+
+ $connection = DriverManager::getConnection($params, $config);
This way you can optimize your schema or generated SQL code with
features that might not be portable for instance, however are
diff --git a/docs/en/reference/query-builder.rst b/docs/en/reference/query-builder.rst
index c34a97fa00a..5b54af3ca07 100644
--- a/docs/en/reference/query-builder.rst
+++ b/docs/en/reference/query-builder.rst
@@ -309,7 +309,7 @@ user-input:
update('users', 'u')
+ ->update('users u')
->set('u.logins', 'u.logins + 1')
->set('u.last_login', '?')
->setParameter(0, $userInputLastLogin)
diff --git a/src/Driver/API/MySQL/ExceptionConverter.php b/src/Driver/API/MySQL/ExceptionConverter.php
index 254489834f2..ad0f0e113a7 100644
--- a/src/Driver/API/MySQL/ExceptionConverter.php
+++ b/src/Driver/API/MySQL/ExceptionConverter.php
@@ -78,7 +78,8 @@ public function convert(Exception $exception, ?Query $query): DriverException
2002,
2005,
2054 => new ConnectionException($exception, $query),
- 2006 => new ConnectionLost($exception, $query),
+ 2006,
+ 4031 => new ConnectionLost($exception, $query),
1048,
1121,
1138,
diff --git a/src/Query/QueryBuilder.php b/src/Query/QueryBuilder.php
index 0d684c9289b..3cbde0f035d 100644
--- a/src/Query/QueryBuilder.php
+++ b/src/Query/QueryBuilder.php
@@ -636,8 +636,8 @@ public function addSelect(string $expression, string ...$expressions): self
*
*
* $qb = $conn->createQueryBuilder()
- * ->delete('users')
- * ->where('users.id = :user_id')
+ * ->delete('users u')
+ * ->where('u.id = :user_id')
* ->setParameter(':user_id', 1);
*
*
@@ -662,9 +662,9 @@ public function delete(string $table): self
*
*
* $qb = $conn->createQueryBuilder()
- * ->update('counters')
- * ->set('counters.value', 'counters.value + 1')
- * ->where('counters.id = ?');
+ * ->update('counters c')
+ * ->set('c.value', 'c.value + 1')
+ * ->where('c.id = ?');
*
*
* @param string $table The table whose rows are subject to the update.
@@ -841,7 +841,7 @@ public function rightJoin(string $fromAlias, string $join, string $alias, ?strin
*
*
* $qb = $conn->createQueryBuilder()
- * ->update('counters', 'c')
+ * ->update('counters c')
* ->set('c.value', 'c.value + 1')
* ->where('c.id = ?');
*
@@ -877,7 +877,7 @@ public function set(string $key, string $value): self
* $or->add($qb->expr()->eq('c.id', 1));
* $or->add($qb->expr()->eq('c.id', 2));
*
- * $qb->update('counters', 'c')
+ * $qb->update('counters c')
* ->set('c.value', 'c.value + 1')
* ->where($or);
*
diff --git a/src/Schema/AbstractAsset.php b/src/Schema/AbstractAsset.php
index 5cbfa4746b7..de5b56f1d52 100644
--- a/src/Schema/AbstractAsset.php
+++ b/src/Schema/AbstractAsset.php
@@ -21,7 +21,8 @@
* The abstract asset allows to reset the name of all assets without publishing this to the public userland.
*
* This encapsulation hack is necessary to keep a consistent state of the database schema. Say we have a list of tables
- * array($tableName => Table($tableName)); if you want to rename the table, you have to make sure
+ * array($tableName => Table($tableName)); if you want to rename the table, you have to make sure this does not get
+ * recreated during schema migration.
*/
abstract class AbstractAsset
{
diff --git a/tests/Driver/VersionAwarePlatformDriverTest.php b/tests/Driver/VersionAwarePlatformDriverTest.php
index 5a2aede9082..a2956f04ee0 100644
--- a/tests/Driver/VersionAwarePlatformDriverTest.php
+++ b/tests/Driver/VersionAwarePlatformDriverTest.php
@@ -38,7 +38,8 @@ public static function mySQLVersionProvider(): array
return [
['5.7.0', MySQLPlatform::class],
['8.0.11', MySQL80Platform::class],
- ['8.4.0', MySQL84Platform::class],
+ ['8.4.1', MySQL84Platform::class],
+ ['9.0.0', MySQL84Platform::class],
['5.5.40-MariaDB-1~wheezy', MariaDBPlatform::class],
['5.5.5-MariaDB-10.2.8+maria~xenial-log', MariaDBPlatform::class],
['10.2.8-MariaDB-10.2.8+maria~xenial-log', MariaDBPlatform::class],