diff --git a/lib/ddl/tests/ddl_test.php b/lib/ddl/tests/ddl_test.php index d5e63a9fa3f..6fed8e1d4ea 100644 --- a/lib/ddl/tests/ddl_test.php +++ b/lib/ddl/tests/ddl_test.php @@ -1655,7 +1655,8 @@ class core_ddl_testcase extends database_driver_testcase { $DB->delete_records('testtable', array()); // This delete performs one DELETE. $dbman->reset_sequence($table); // Using xmldb object. - $this->assertEquals(1, $DB->insert_record('testtable', (object)array('course'=>13))); + $this->assertEquals(1, $DB->insert_record('testtable', (object)array('course'=>13)), + 'Some versions of MySQL 5.6.x are known to not support lowering of auto-increment numbers.'); $DB->import_record('testtable', $record); $dbman->reset_sequence($tablename); // Using string. diff --git a/lib/testing/classes/util.php b/lib/testing/classes/util.php index ba4f4915170..097bbd1076f 100644 --- a/lib/testing/classes/util.php +++ b/lib/testing/classes/util.php @@ -570,7 +570,67 @@ abstract class testing_util { $empties = self::guess_unmodified_empty_tables(); + $borkedmysql = false; + if ($DB->get_dbfamily() === 'mysql') { + $version = $DB->get_server_info(); + if (version_compare($version['version'], '5.6.0') == 1 and version_compare($version['version'], '5.6.16') == -1) { + // Everything that comes from Oracle is evil! + // + // See http://dev.mysql.com/doc/refman/5.6/en/alter-table.html + // You cannot reset the counter to a value less than or equal to to the value that is currently in use. + // + // From 5.6.16 release notes: + // InnoDB: The ALTER TABLE INPLACE algorithm would fail to decrease the auto-increment value. + // (Bug #17250787, Bug #69882) + $borkedmysql = true; + + } else if (version_compare($version['version'], '10.0.0') == 1) { + // And MariaDB is no better! + // Let's hope they pick the patch sometime later... + $borkedmysql = true; + } + } + + if ($borkedmysql) { + $mysqlsequences = array(); + $prefix = $DB->get_prefix(); + $rs = $DB->get_recordset_sql("SHOW TABLE STATUS LIKE ?", array($prefix.'%')); + foreach ($rs as $info) { + $table = strtolower($info->name); + if (strpos($table, $prefix) !== 0) { + // Incorrect table match caused by _ char. + continue; + } + if (!is_null($info->auto_increment)) { + $table = preg_replace('/^'.preg_quote($prefix, '/').'/', '', $table); + $mysqlsequences[$table] = $info->auto_increment; + } + } + } + foreach ($data as $table => $records) { + if ($borkedmysql) { + if (empty($records) and isset($empties[$table])) { + continue; + } + + if (isset($structure[$table]['id']) and $structure[$table]['id']->auto_increment) { + $current = $DB->get_records($table, array(), 'id ASC'); + if ($current == $records) { + if (isset($mysqlsequences[$table]) and $mysqlsequences[$table] == $structure[$table]['id']->auto_increment) { + continue; + } + } + } + + // Use TRUNCATE as a workaround and reinsert everything. + $DB->delete_records($table, null); + foreach ($records as $record) { + $DB->import_record($table, $record, false, true); + } + continue; + } + if (empty($records)) { if (isset($empties[$table])) { // table was not modified and is empty