Completed
Push — master ( 599977...a7d112 )
by Thomas
10:10
created

Collation::getAllNonUTF8BinTables()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 35
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 25
nc 8
nop 1
dl 0
loc 35
rs 8.5806
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Morris Jobke <[email protected]>
4
 * @author Robin Appelman <[email protected]>
5
 * @author Thomas Müller <[email protected]>
6
 *
7
 * @copyright Copyright (c) 2016, ownCloud GmbH.
8
 * @license AGPL-3.0
9
 *
10
 * This code is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License, version 3,
12
 * as published by the Free Software Foundation.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License, version 3,
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
21
 *
22
 */
23
24
namespace OC\Repair;
25
26
use Doctrine\DBAL\Platforms\MySqlPlatform;
27
use OCP\IDBConnection;
28
use OCP\Migration\IOutput;
29
use OCP\Migration\IRepairStep;
30
31
class Collation implements IRepairStep {
32
33
	/** @var \OCP\IConfig */
34
	protected $config;
35
36
	/** @var IDBConnection */
37
	protected $connection;
38
39
	/**
40
	 * @param \OCP\IConfig $config
41
	 * @param IDBConnection $connection
42
	 */
43
	public function __construct($config, IDBConnection $connection) {
44
		$this->connection = $connection;
45
		$this->config = $config;
46
	}
47
48
	public function getName() {
49
		return 'Repair MySQL collation';
50
	}
51
52
	/**
53
	 * Fix mime types
54
	 */
55
	public function run(IOutput $output) {
56
		if (!$this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
57
			$output->info('Not a mysql database -> nothing to do');
58
			return;
59
		}
60
61
		$characterSet = $this->config->getSystemValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
62
63
		$tables = $this->getAllNonUTF8BinTables($this->connection);
64
		foreach ($tables as $table) {
65
			$output->info("Change collation for $table ...");
66
			if ($characterSet === 'utf8mb4') {
67
				// need to set row compression first
68
				$query = $this->connection->prepare('ALTER TABLE `' . $table . '` ROW_FORMAT=COMPRESSED;');
69
				$query->execute();
70
			}
71
			$query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET ' . $characterSet . ' COLLATE ' . $characterSet . '_bin;');
72
			$query->execute();
73
		}
74
		if (empty($tables)) {
75
			$output->info('All tables already have the correct collation -> nothing to do');
76
		}
77
	}
78
79
	/**
80
	 * @param IDBConnection $connection
81
	 * @return string[]
82
	 */
83
	protected function getAllNonUTF8BinTables(IDBConnection $connection) {
84
		$dbName = $this->config->getSystemValue("dbname");
85
		$characterSet = $this->config->getSystemValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
86
87
		// fetch tables by columns
88
		$statement = $connection->executeQuery(
89
			"SELECT DISTINCT(TABLE_NAME) AS `table`" .
90
			"	FROM INFORMATION_SCHEMA . COLUMNS" .
91
			"	WHERE TABLE_SCHEMA = ?" .
92
			"	AND (COLLATION_NAME <> '" . $characterSet . "_bin' OR CHARACTER_SET_NAME <> '" . $characterSet . "')" .
93
			"	AND TABLE_NAME LIKE \"*PREFIX*%\"",
94
			[$dbName]
95
		);
96
		$rows = $statement->fetchAll();
97
		$result = [];
98
		foreach ($rows as $row) {
99
			$result[$row['table']] = true;
100
		}
101
102
		// fetch tables by collation
103
		$statement = $connection->executeQuery(
104
			"SELECT DISTINCT(TABLE_NAME) AS `table`" .
105
			"	FROM INFORMATION_SCHEMA . TABLES" .
106
			"	WHERE TABLE_SCHEMA = ?" .
107
			"	AND TABLE_COLLATION <> '" . $characterSet . "_bin'" .
108
			"	AND TABLE_NAME LIKE \"*PREFIX*%\"",
109
			[$dbName]
110
		);
111
		$rows = $statement->fetchAll();
112
		foreach ($rows as $row) {
113
			$result[$row['table']] = true;
114
		}
115
116
		return array_keys($result);
117
	}
118
}
119
120