'$itflow_collation' ORDER BY TABLE_NAME, ORDINAL_POSITION"); while ($itflow_result && $itflow_row = mysqli_fetch_assoc($itflow_result)) { // Binary on purpose if (substr((string) $itflow_row['collation_name'], -4) === '_bin') { continue; } $itflow_table_columns[$itflow_row['table_name']][] = $itflow_row['column_name']; } // A text column's type as SHOW CREATE TABLE writes it. An enum's values are quoted, // with a quote inside one doubled. $itflow_text_type = "(?:var)?char\\(\\d+\\)|(?:tiny|medium|long)?text|(?:enum|set)\\('(?:[^']|'')*'(?:,'(?:[^']|'')*')*\\)"; try { mysqli_query($mysqli, "SET @itflow_sql_mode = @@SESSION.sql_mode"); mysqli_query($mysqli, "SET SESSION sql_mode = REPLACE(REPLACE(@@SESSION.sql_mode, 'NO_ZERO_IN_DATE', ''), 'NO_ZERO_DATE', '')"); } catch (Throwable $itflow_error) { // Carry on with the mode as it is - records may then be one of the tables left } foreach ($itflow_tables as $itflow_table) { // Not on this install if (!isset($itflow_table_collations[$itflow_table])) { continue; } $itflow_columns = $itflow_table_columns[$itflow_table] ?? []; $itflow_default_differs = $itflow_table_collations[$itflow_table] !== $itflow_collation; if (!$itflow_columns && !$itflow_default_differs) { continue; } try { $itflow_changes = []; if ($itflow_columns) { $itflow_result = mysqli_query($mysqli, "SHOW CREATE TABLE `$itflow_table`"); $itflow_row = $itflow_result ? mysqli_fetch_row($itflow_result) : null; if (!$itflow_row || empty($itflow_row[1])) { throw new RuntimeException("its definition could not be read"); } foreach ($itflow_columns as $itflow_column) { // `name` type [CHARACTER SET x] [COLLATE y] and the rest - NOT NULL, DEFAULT, // COMMENT - which goes back exactly as the server wrote it if (!preg_match('/^[A-Za-z0-9_]+$/', $itflow_column) || !preg_match('/^\s*[`"]?' . $itflow_column . '[`"]?\s+(' . $itflow_text_type . ')(?:\s+CHARACTER SET\s+\w+)?(?:\s+COLLATE\s+\w+)?(.*?),?\s*$/mi', $itflow_row[1], $itflow_match)) { throw new RuntimeException("the definition of its column $itflow_column was not understood"); } $itflow_changes[] = "MODIFY `$itflow_column` {$itflow_match[1]} CHARACTER SET utf8mb4 COLLATE $itflow_collation{$itflow_match[2]}"; } } if ($itflow_default_differs) { $itflow_changes[] = "DEFAULT CHARACTER SET utf8mb4 COLLATE $itflow_collation"; } if (!mysqli_query($mysqli, "ALTER TABLE `$itflow_table` " . implode(', ', $itflow_changes))) { throw new RuntimeException(mysqli_error($mysqli)); } } catch (Throwable $itflow_error) { $itflow_message = "Database update 3.6.5 left the table $itflow_table with the collation it had (the rest of the update went on): " . $itflow_error->getMessage(); error_log("ITFlow: $itflow_message"); if (function_exists('logApp')) { try { logApp('Database Update', 'warning', $itflow_message); } catch (Throwable $itflow_error) { // The PHP error log has it } } } } try { mysqli_query($mysqli, "SET SESSION sql_mode = IFNULL(@itflow_sql_mode, @@SESSION.sql_mode)"); } catch (Throwable $itflow_error) { // The connection ends with the update } unset($itflow_collation, $itflow_tables, $itflow_table_collations, $itflow_table_columns, $itflow_result, $itflow_row, $itflow_text_type, $itflow_table, $itflow_columns, $itflow_default_differs, $itflow_changes, $itflow_column, $itflow_match, $itflow_error, $itflow_message);