MDL-58729 database: Improve performance of CLI tool.
authorAdrian Greeve <adrian@moodle.com>
Mon, 12 Jun 2017 04:02:08 +0000 (12:02 +0800)
committerAdrian Greeve <adrian@moodle.com>
Mon, 12 Jun 2017 06:03:36 +0000 (14:03 +0800)
Imporve the speed with which mysql_collation converts to
a different collation.

admin/cli/mysql_collation.php

index adaadbb..ae3c709 100644 (file)
@@ -53,7 +53,7 @@ Options:
 -h, --help            Print out this help
 
 Example:
-\$ sudo -u www-data /usr/bin/php admin/cli/mysql_collation.php --collation=utf8_general_ci
+\$ sudo -u www-data /usr/bin/php admin/cli/mysql_collation.php --collation=utf8mb4_unicode_ci
 ";
 
 if (!empty($options['collation'])) {
@@ -145,9 +145,22 @@ if (!empty($options['collation'])) {
             $skipped++;
 
         } else {
-            $DB->change_database_structure("ALTER TABLE $table->name DEFAULT CHARACTER SET $charset DEFAULT COLLATE = $collation");
-            echo "CONVERTED\n";
-            $converted++;
+            try {
+                $DB->change_database_structure("ALTER TABLE $table->name CONVERT TO CHARACTER SET $charset COLLATE $collation");
+                echo "CONVERTED\n";
+                $converted++;
+            } catch (ddl_exception $e) {
+                $result = mysql_set_row_format($table->name, $charset, $collation, $engine);
+                if ($result) {
+                    echo "CONVERTED\n";
+                    $converted++;
+                } else {
+                    // We don't know what the problem is. Stop the conversion.
+                    cli_error("Error: Tried to convert $table->name, but there was a problem. Please check the details of this
+                            table and try again.");
+                    die();
+                }
+            }
         }
 
         $sql = "SHOW FULL COLUMNS FROM $table->name WHERE collation IS NOT NULL";
@@ -290,3 +303,26 @@ function mysql_get_column_collations($tablename) {
     $rs->close();
     return $collations;
 }
+
+function mysql_set_row_format($tablename, $charset, $collation, $engine) {
+    global $DB;
+
+    $sql = "SELECT row_format
+              FROM INFORMATION_SCHEMA.TABLES
+             WHERE table_schema = DATABASE() AND table_name = ?";
+    $rs = $DB->get_record_sql($sql, array($tablename));
+    if ($rs) {
+        if ($rs->row_format == 'Compact' || $rs->row_format == 'Redundant') {
+            $rowformat = $DB->get_row_format_sql($engine, $collation);
+            // Try to convert to compressed format and then try updating the collation again.
+            $DB->change_database_structure("ALTER TABLE $tablename $rowformat");
+            $DB->change_database_structure("ALTER TABLE $tablename CONVERT TO CHARACTER SET $charset COLLATE $collation");
+        } else {
+            // Row format may not be the problem. Can not diagnose problem. Send fail reply.
+            return false;
+        }
+    } else {
+        return false;
+    }
+    return true;
+}