Keep collations at utf8mb4_general_ci going forward: functions.php now ends by calling databaseConnectionCollation, which runs SET collation_connection = 'utf8mb4_general_ci' on the connection config.php opened, so a string the server makes itself, CAST(x AS CHAR) for one, matches the tables where on MySQL 8 it came out utf8mb4_0900_ai_ci and failed beside a column with Illegal mix of collations, on a new install as much as an upgraded one; only the collation is set and not the character set, no SET NAMES and no mysqli_set_charset, because on a server that defaults to latin1 the connection has always been latin1 and changing it shows every accented letter already stored as two wrong ones, where setting collation_connection alone leaves what is stored and what is stored after the same; admin/database_updates.php calls databaseCollationRepair after a run that applied at least one database update and finished, so a table a migration creates without a COLLATE is given the collation db.sql has in the same run, with what it changed and what it could not going to App Logs and to the output of scripts/update_cli.php, a table it cannot change left as it was and never failing the update, and a run that stops at a failed migration leaving this for the run that finishes; run on MySQL 8.0 and MariaDB 10.11, on a latin1 server default and through update_cli.php --update_db with a migration written as 2.4.1 was; CONTRIBUTING.md and the 26.11.7 changelog section say so

This commit is contained in:
johnnyq
2026-11-11 20:52:46 -05:00
parent bce68aac6a
commit 69fd43051f
6 changed files with 84 additions and 1 deletions

View File

@@ -30,6 +30,7 @@ define("FROM_DB_UPDATER", true);
// Outputs for the caller (update_cli.php)
$database_updates_applied = []; // Versions successfully applied this run
$database_updates_error = null; // "version: error message" if a migration failed
$database_updates_collations = null; // ['changed' => [table, ...], 'failed' => [table => why]] when collations were checked
// Collect and order the migration files by version (glob sorts alphabetically,
// which would put 2.4.10 before 2.4.9 - version_compare gets it right)
@@ -67,3 +68,27 @@ foreach ($database_update_files as $version => $file) {
$database_current_version = $version;
$database_updates_applied[] = $version;
}
// After the updates, every table against db.sql's collation (functions/database_collation.php).
// A migration that creates a table without a COLLATE gives it the server's default - right on
// the server it was written on, and utf8mb4_0900_ai_ci on MySQL 8 or utf8mb4_uca1400_ai_ci on
// MariaDB 11.5 and later, where the first query to read it beside another table then fails.
// 2.1.6 to 2.4.1 did exactly that, and it took 26.11.4's dashboard to show it. Putting it
// right here, in the run that made the table, means such a slip never reaches a page.
//
// Only when this run applied something and finished: a run that stopped has the database
// part-way, and the re-run that completes it comes through here. Nothing here can fail the
// update - a table that can't be changed is left as it was and said so.
if ($database_updates_applied && !$database_updates_error && function_exists('databaseCollationRepair')) {
try {
$database_updates_collations = databaseCollationRepair();
if ($database_updates_collations['changed']) {
logApp('Database Update', 'info', "Gave " . (count($database_updates_collations['changed']) === 1 ? '1 table' : count($database_updates_collations['changed']) . ' tables') . " the collation db.sql has after the database update: " . implode(', ', $database_updates_collations['changed']));
}
foreach ($database_updates_collations['failed'] as $table => $why) {
logApp('Database Update', 'warning', "After the database update the table $table doesn't have the collation db.sql has, and could not be given it: $why");
}
} catch (Throwable $e) {
error_log("ITFlow database update: checking collations failed: " . $e->getMessage());
}
}