From 2251dbea2bb8799177763009ed3cf03bea974448 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Fri, 12 Jun 2026 15:32:07 +0200 Subject: [PATCH 1/2] chore: bump MySQL to min 8.4 and support 9.7 - Version 8.0 is out-of-support. - Version 8.4 is now the oldest LTS. - New LTS is 9.7 Signed-off-by: Ferdinand Thiessen --- .github/workflows/phpunit-mysql-sharding.yml | 14 +++++++------- .github/workflows/phpunit-mysql.yml | 6 +++--- .../settings/lib/SetupChecks/SupportedDatabase.php | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/phpunit-mysql-sharding.yml b/.github/workflows/phpunit-mysql-sharding.yml index 9c02db9212654..b03e2e8484e86 100644 --- a/.github/workflows/phpunit-mysql-sharding.yml +++ b/.github/workflows/phpunit-mysql-sharding.yml @@ -57,9 +57,9 @@ jobs: fail-fast: false matrix: include: - - mysql-versions: '8.0' - php-versions: '8.3' - mysql-versions: '8.4' + php-versions: '8.3' + - mysql-versions: '9.7' php-versions: '8.5' name: Sharding - MySQL ${{ matrix.mysql-versions }} (PHP ${{ matrix.php-versions }}) - database tests @@ -72,7 +72,7 @@ jobs: options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3 mysql: - image: ghcr.io/nextcloud/continuous-integration-mysql-${{ matrix.mysql-versions }}:latest # zizmor: ignore[unpinned-images] + image: mysql:${{ matrix.mysql-versions }} # zizmor: ignore[unpinned-images] ports: - 4444:3306/tcp env: @@ -82,7 +82,7 @@ jobs: MYSQL_DATABASE: oc_autotest options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 10 shard1: - image: ghcr.io/nextcloud/continuous-integration-mysql-${{ matrix.mysql-versions }}:latest # zizmor: ignore[unpinned-images] + image: mysql:${{ matrix.mysql-versions }} # zizmor: ignore[unpinned-images] ports: - 5001:3306/tcp env: @@ -92,7 +92,7 @@ jobs: MYSQL_DATABASE: nextcloud options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 10 shard2: - image: ghcr.io/nextcloud/continuous-integration-mysql-${{ matrix.mysql-versions }}:latest # zizmor: ignore[unpinned-images] + image: mysql:${{ matrix.mysql-versions }} # zizmor: ignore[unpinned-images] ports: - 5002:3306/tcp env: @@ -102,7 +102,7 @@ jobs: MYSQL_DATABASE: nextcloud options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 10 shard3: - image: ghcr.io/nextcloud/continuous-integration-mysql-${{ matrix.mysql-versions }}:latest # zizmor: ignore[unpinned-images] + image: mysql:${{ matrix.mysql-versions }} # zizmor: ignore[unpinned-images] ports: - 5003:3306/tcp env: @@ -112,7 +112,7 @@ jobs: MYSQL_DATABASE: nextcloud options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 10 shard4: - image: ghcr.io/nextcloud/continuous-integration-mysql-${{ matrix.mysql-versions }}:latest # zizmor: ignore[unpinned-images] + image: mysql:${{ matrix.mysql-versions }} # zizmor: ignore[unpinned-images] ports: - 5004:3306/tcp env: diff --git a/.github/workflows/phpunit-mysql.yml b/.github/workflows/phpunit-mysql.yml index 55cf3b157133c..d31b8cc97bb08 100644 --- a/.github/workflows/phpunit-mysql.yml +++ b/.github/workflows/phpunit-mysql.yml @@ -60,9 +60,9 @@ jobs: fail-fast: false matrix: include: - - mysql-versions: '8.0' - php-versions: '8.3' - mysql-versions: '8.4' + php-versions: '8.3' + - mysql-versions: '9.7' php-versions: '8.5' name: MySQL ${{ matrix.mysql-versions }} (PHP ${{ matrix.php-versions }}) - database tests @@ -75,7 +75,7 @@ jobs: options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3 mysql: - image: ghcr.io/nextcloud/continuous-integration-mysql-${{ matrix.mysql-versions }}:latest # zizmor: ignore[unpinned-images] + image: mysql:${{ matrix.mysql-versions }} # zizmor: ignore[unpinned-images] ports: - 4444:3306/tcp env: diff --git a/apps/settings/lib/SetupChecks/SupportedDatabase.php b/apps/settings/lib/SetupChecks/SupportedDatabase.php index cf5c949c0ce9d..2edb26795e4a3 100644 --- a/apps/settings/lib/SetupChecks/SupportedDatabase.php +++ b/apps/settings/lib/SetupChecks/SupportedDatabase.php @@ -19,8 +19,8 @@ class SupportedDatabase implements ISetupCheck { private const MIN_MARIADB = '10.6'; private const MAX_MARIADB = '11.8'; - private const MIN_MYSQL = '8.0'; - private const MAX_MYSQL = '8.4'; + private const MIN_MYSQL = '8.4'; + private const MAX_MYSQL = '9.7'; private const MIN_POSTGRES = '14'; private const MAX_POSTGRES = '18'; private const MIN_ORACLE = '12.2'; From 43dc92df527b1ec7c7195013237ac21b381a80e4 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Fri, 12 Jun 2026 16:28:44 +0200 Subject: [PATCH 2/2] fix: add handling for MD5 on new MySQL and deprecate MD5 SQL function Signed-off-by: Ferdinand Thiessen --- .github/workflows/phpunit-mysql-sharding.yml | 7 +++++ build/psalm-baseline.xml | 10 +++++++ lib/private/Setup/MySQL.php | 29 ++++++++++++++----- .../DB/QueryBuilder/IFunctionBuilder.php | 1 + 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/.github/workflows/phpunit-mysql-sharding.yml b/.github/workflows/phpunit-mysql-sharding.yml index b03e2e8484e86..96ba7a8c4feb5 100644 --- a/.github/workflows/phpunit-mysql-sharding.yml +++ b/.github/workflows/phpunit-mysql-sharding.yml @@ -151,6 +151,13 @@ jobs: echo "SET GLOBAL sql_mode=(SELECT CONCAT(@@sql_mode,',ONLY_FULL_GROUP_BY'));" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword echo "SELECT @@sql_mode;" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword + - name: Enable MD5 MySQL support + if: matrix.mysql-versions == '9.7' + run: | + for MYSQL_PORT in 4444 5001 5002 5003 5004; do + echo "INSTALL COMPONENT 'file://component_classic_hashing';" | mysql -h 127.0.0.1 -P $MYSQL_PORT -u root -prootpassword + done + - name: Set up Nextcloud env: DB_PORT: 4444 diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index 3abce0fbe43bb..329f3732fb029 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -1420,6 +1420,11 @@ + + + + + @@ -3232,6 +3237,11 @@ request->server]]> + + + + + diff --git a/lib/private/Setup/MySQL.php b/lib/private/Setup/MySQL.php index 492d83d3cd271..b2b468d699929 100644 --- a/lib/private/Setup/MySQL.php +++ b/lib/private/Setup/MySQL.php @@ -8,7 +8,6 @@ namespace OC\Setup; -use Doctrine\DBAL\Platforms\MySQL80Platform; use Doctrine\DBAL\Platforms\MySQL84Platform; use OC\DatabaseSetupException; use OC\DB\ConnectionAdapter; @@ -39,6 +38,28 @@ public function setupDatabase(): void { 'dbpassword' => $this->dbPassword, ]); + // for MD5 support + // In MySQL 9+ MD5 has been deprecated and is only available as a component. + // Until we dropped the support for it on the function builder, we need to load the component. + if ($connection->getDatabasePlatform() instanceof MySQL84Platform) { + $statement = $connection->prepare("SHOW VARIABLES LIKE 'version';"); + $result = $statement->executeQuery(); + $row = $result->fetchAssociative(); + $version = $row['Value']; + [$major, ] = explode('.', strtolower($version)); + if ((int)$major >= 9) { + // check if the component is already loaded, if not load it + $statement = $connection->prepare("SELECT COUNT(*) FROM mysql.component WHERE component_urn = 'file://component_classic_hashing';"); + $result = $statement->executeQuery(); + $count = $result->fetchOne(); + if ($count !== false && (int)$count === 0) { + // not yet loaded + $statement = $connection->prepare("INSTALL COMPONENT 'file://component_classic_hashing';"); + $statement->executeStatement(); + } + } + } + //create the database $this->createDatabase($connection); @@ -103,12 +124,6 @@ private function createDBUser(IDBConnection $connection): void { $connection->executeStatement($query, [$name,$password]); $query = "CREATE USER ?@'%' IDENTIFIED WITH caching_sha2_password BY ?"; $connection->executeStatement($query, [$name,$password]); - } elseif ($connection->getDatabasePlatform() instanceof Mysql80Platform) { - // TODO: Remove this elseif section as soon as MySQL 8.0 is out-of-support (after April 2026) - $query = "CREATE USER ?@'localhost' IDENTIFIED WITH mysql_native_password BY ?"; - $connection->executeStatement($query, [$name,$password]); - $query = "CREATE USER ?@'%' IDENTIFIED WITH mysql_native_password BY ?"; - $connection->executeStatement($query, [$name,$password]); } else { $query = "CREATE USER ?@'localhost' IDENTIFIED BY ?"; $connection->executeStatement($query, [$name,$password]); diff --git a/lib/public/DB/QueryBuilder/IFunctionBuilder.php b/lib/public/DB/QueryBuilder/IFunctionBuilder.php index 2667f1487969a..f792e05cf6046 100644 --- a/lib/public/DB/QueryBuilder/IFunctionBuilder.php +++ b/lib/public/DB/QueryBuilder/IFunctionBuilder.php @@ -20,6 +20,7 @@ interface IFunctionBuilder { * * @return IQueryFunction * @since 12.0.0 + * @deprecated 35.0.0 - MD5 is not considered secure anymore, thus most databases have or will drop support for this function */ public function md5($input): IQueryFunction;