]> source.dussan.org Git - nextcloud-server.git/commitdiff
Add repair step to set MySQL collation to utf8_bin
authorRobin Appelman <icewind@owncloud.com>
Mon, 7 Jul 2014 15:37:35 +0000 (17:37 +0200)
committerThomas Müller <thomas.mueller@tmit.eu>
Tue, 8 Jul 2014 13:12:07 +0000 (15:12 +0200)
Set default collation of mysql connection to utf8_bin
Set utf_bin as default collation for new tables

lib/private/db/mdb2schemareader.php
lib/private/repair.php
lib/private/setup/mysql.php
lib/repair/collation.php [new file with mode: 0644]
tests/lib/repair/repaircollation.php [new file with mode: 0644]

index 61f58a1f200dcf6c580e152c96937706b6402d50..288eef5cda0159857d1cdd32724eb4a92b4a8a98 100644 (file)
@@ -82,6 +82,7 @@ class MDB2SchemaReader {
                                        $name = str_replace('*dbprefix*', $this->DBTABLEPREFIX, $name);
                                        $name = $this->platform->quoteIdentifier($name);
                                        $table = $schema->createTable($name);
+                                       $table->addOption('collate', 'utf8_bin');
                                        break;
                                case 'create':
                                case 'overwrite':
index 89886dd9316fad38b982831e431d3788e8502715..e6943c5d0575b7a6a520e13478d0179acd0f41dc 100644 (file)
@@ -81,7 +81,8 @@ class Repair extends BasicEmitter {
         */
        public static function getBeforeUpgradeRepairSteps() {
                return array(
-                       new \OC\Repair\InnoDB()
+                       new \OC\Repair\InnoDB(),
+                       new \OC\Repair\Collation(\OC::$server->getConfig(), \OC_DB::getConnection())
                );
        }
 
index b2c28173b1c61a57fb964ada4d28d7f15d5b77e7..3327965fb49e6301be1a43ac7c063f223f1ad09d 100644 (file)
@@ -61,7 +61,7 @@ class MySQL extends AbstractDatabase {
                $name = $this->dbname;
                $user = $this->dbuser;
                //we cant use OC_BD functions here because we need to connect as the administrative user.
-               $query = "CREATE DATABASE IF NOT EXISTS `$name`";
+               $query = "CREATE DATABASE IF NOT EXISTS `$name` CHARACTER SET utf8 COLLATE utf8_bin;";
                $result = mysql_query($query, $connection);
                if(!$result) {
                        $entry = $this->trans->t('DB Error: "%s"', array(mysql_error($connection))) . '<br />';
diff --git a/lib/repair/collation.php b/lib/repair/collation.php
new file mode 100644 (file)
index 0000000..2247cf8
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Repair;
+
+use Doctrine\DBAL\Platforms\MySqlPlatform;
+use OC\Hooks\BasicEmitter;
+
+class Collation extends BasicEmitter implements \OC\RepairStep {
+       /**
+        * @var \OCP\IConfig
+        */
+       protected $config;
+
+       /**
+        * @var \OC\DB\Connection
+        */
+       protected $connection;
+
+       /**
+        * @param \OCP\IConfig $config
+        * @param \OC\DB\Connection $connection
+        */
+       public function __construct($config, $connection) {
+               $this->connection = $connection;
+               $this->config = $config;
+       }
+
+       public function getName() {
+               return 'Repair MySQL collation';
+       }
+
+       /**
+        * Fix mime types
+        */
+       public function run() {
+               if (!$this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
+                       $this->emit('\OC\Repair', 'info', array('Not a mysql database -> nothing to no'));
+                       return;
+               }
+
+               $tables = $this->getAllNonUTF8BinTables($this->connection);
+               foreach ($tables as $table) {
+                       $query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;');
+                       $query->execute();
+               }
+       }
+
+       /**
+        * @param \Doctrine\DBAL\Connection $connection
+        * @return string[]
+        */
+       protected function getAllNonUTF8BinTables($connection) {
+               $dbName = $this->config->getSystemValue("dbname");
+               $rows = $connection->fetchAll(
+                       "SELECT DISTINCT(TABLE_NAME) AS `table`" .
+                       "       FROM INFORMATION_SCHEMA . COLUMNS" .
+                       "       WHERE TABLE_SCHEMA = ?" .
+                       "       AND (COLLATION_NAME <> 'utf8_bin' OR CHARACTER_SET_NAME <> 'utf8')" .
+                       "       AND TABLE_NAME LIKE \"*PREFIX*%\"",
+                       array($dbName)
+               );
+               $result = array();
+               foreach ($rows as $row) {
+                       $result[] = $row['table'];
+               }
+               return $result;
+       }
+}
+
diff --git a/tests/lib/repair/repaircollation.php b/tests/lib/repair/repaircollation.php
new file mode 100644 (file)
index 0000000..362feb8
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Copyright (c) 2014 Thomas Müller <deepdiver@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+class TestCollationRepair extends \OC\Repair\Collation {
+       /**
+        * @param \Doctrine\DBAL\Connection $connection
+        * @return string[]
+        */
+       public function getAllNonUTF8BinTables($connection) {
+               return parent::getAllNonUTF8BinTables($connection);
+       }
+}
+
+/**
+ * Tests for the converting of MySQL tables to InnoDB engine
+ *
+ * @see \OC\Repair\RepairMimeTypes
+ */
+class TestRepairCollation extends PHPUnit_Framework_TestCase {
+
+       /**
+        * @var TestCollationRepair
+        */
+       private $repair;
+
+       /**
+        * @var \Doctrine\DBAL\Connection
+        */
+       private $connection;
+
+       /**
+        * @var string
+        */
+       private $tableName;
+
+       /**
+        * @var \OCP\IConfig
+        */
+       private $config;
+
+       public function setUp() {
+               $this->connection = \OC_DB::getConnection();
+               $this->config = \OC::$server->getConfig();
+               if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\MySqlPlatform) {
+                       $this->markTestSkipped("Test only relevant on MySql");
+               }
+
+               $dbPrefix = $this->config->getSystemValue("dbtableprefix");
+               $this->tableName = uniqid($dbPrefix . "_collation_test");
+               $this->connection->exec("CREATE TABLE $this->tableName(text VARCHAR(16)) COLLATE utf8_unicode_ci");
+
+               $this->repair = new TestCollationRepair($this->config, $this->connection);
+       }
+
+       public function tearDown() {
+               $this->connection->getSchemaManager()->dropTable($this->tableName);
+       }
+
+       public function testCollationConvert() {
+               $tables = $this->repair->getAllNonUTF8BinTables($this->connection);
+               $this->assertGreaterThanOrEqual(1, count($tables));
+
+               $this->repair->run();
+
+               $tables = $this->repair->getAllNonUTF8BinTables($this->connection);
+               $this->assertCount(0, $tables);
+       }
+}