Add config option to update charset of mysql to utf8mb4
* fully optional * requires additional options set in the database
This commit is contained in:
parent
972e560e72
commit
cc28f82b36
|
@ -129,6 +129,7 @@ $CONFIG = array(
|
||||||
*/
|
*/
|
||||||
'dbtableprefix' => '',
|
'dbtableprefix' => '',
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether the Nextcloud instance was installed successfully; ``true``
|
* Indicates whether the Nextcloud instance was installed successfully; ``true``
|
||||||
* indicates a successful installation, and ``false`` indicates an unsuccessful
|
* indicates a successful installation, and ``false`` indicates an unsuccessful
|
||||||
|
@ -1079,6 +1080,34 @@ $CONFIG = array(
|
||||||
*/
|
*/
|
||||||
'sqlite.journal_mode' => 'DELETE',
|
'sqlite.journal_mode' => 'DELETE',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this setting is set to true MySQL can handle 4 byte characters instead of
|
||||||
|
* 3 byte characters
|
||||||
|
*
|
||||||
|
* MySQL requires a special setup for longer indexes (> 767 bytes) which are
|
||||||
|
* needed:
|
||||||
|
*
|
||||||
|
* [mysqld]
|
||||||
|
* innodb_large_prefix=true
|
||||||
|
* innodb_file_format=barracuda
|
||||||
|
* innodb_file_per_table=true
|
||||||
|
*
|
||||||
|
* Tables will be created with
|
||||||
|
* * character set: utf8mb4
|
||||||
|
* * collation: utf8mb4_bin
|
||||||
|
* * row_format: compressed
|
||||||
|
*
|
||||||
|
* See:
|
||||||
|
* https://dev.mysql.com/doc/refman/5.7/en/charset-unicode-utf8mb4.html
|
||||||
|
* https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_large_prefix
|
||||||
|
* https://mariadb.com/kb/en/mariadb/xtradbinnodb-server-system-variables/#innodb_large_prefix
|
||||||
|
* http://www.tocker.ca/2013/10/31/benchmarking-innodb-page-compression-performance.html
|
||||||
|
* http://mechanics.flite.com/blog/2014/07/29/using-innodb-large-prefix-to-avoid-error-1071/
|
||||||
|
*
|
||||||
|
* WARNING: EXPERIMENTAL
|
||||||
|
*/
|
||||||
|
'mysql.utf8mb4' => false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database types that are supported for installation.
|
* Database types that are supported for installation.
|
||||||
*
|
*
|
||||||
|
|
|
@ -83,7 +83,7 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) {
|
||||||
$application->add(new OC\Core\Command\Config\System\SetConfig(\OC::$server->getSystemConfig()));
|
$application->add(new OC\Core\Command\Config\System\SetConfig(\OC::$server->getSystemConfig()));
|
||||||
|
|
||||||
$application->add(new OC\Core\Command\Db\GenerateChangeScript());
|
$application->add(new OC\Core\Command\Db\GenerateChangeScript());
|
||||||
$application->add(new OC\Core\Command\Db\ConvertType(\OC::$server->getConfig(), new \OC\DB\ConnectionFactory()));
|
$application->add(new OC\Core\Command\Db\ConvertType(\OC::$server->getConfig(), new \OC\DB\ConnectionFactory(\OC::$server->getSystemConfig())));
|
||||||
|
|
||||||
$application->add(new OC\Core\Command\Encryption\Disable(\OC::$server->getConfig()));
|
$application->add(new OC\Core\Command\Encryption\Disable(\OC::$server->getConfig()));
|
||||||
$application->add(new OC\Core\Command\Encryption\Enable(\OC::$server->getConfig(), \OC::$server->getEncryptionManager()));
|
$application->add(new OC\Core\Command\Encryption\Enable(\OC::$server->getConfig(), \OC::$server->getEncryptionManager()));
|
||||||
|
|
|
@ -39,7 +39,8 @@ class AdapterMySQL extends Adapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fixupStatement($statement) {
|
public function fixupStatement($statement) {
|
||||||
$statement = str_replace(' ILIKE ', ' COLLATE utf8_general_ci LIKE ', $statement);
|
$characterSet = \OC::$server->getConfig()->getSystemValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
|
||||||
|
$statement = str_replace(' ILIKE ', ' COLLATE ' . $characterSet . '_general_ci LIKE ', $statement);
|
||||||
return $statement;
|
return $statement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ namespace OC\DB;
|
||||||
use Doctrine\DBAL\Event\Listeners\OracleSessionInit;
|
use Doctrine\DBAL\Event\Listeners\OracleSessionInit;
|
||||||
use Doctrine\DBAL\Event\Listeners\SQLSessionInit;
|
use Doctrine\DBAL\Event\Listeners\SQLSessionInit;
|
||||||
use Doctrine\DBAL\Event\Listeners\MysqlSessionInit;
|
use Doctrine\DBAL\Event\Listeners\MysqlSessionInit;
|
||||||
|
use OC\SystemConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes care of creating and configuring Doctrine connections.
|
* Takes care of creating and configuring Doctrine connections.
|
||||||
|
@ -64,6 +65,12 @@ class ConnectionFactory {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public function __construct(SystemConfig $systemConfig) {
|
||||||
|
if($systemConfig->getValue('mysql.utf8mb4', false)) {
|
||||||
|
$defaultConnectionParams['mysql']['charset'] = 'utf8mb4';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get default connection parameters for a given DBMS.
|
* @brief Get default connection parameters for a given DBMS.
|
||||||
* @param string $type DBMS type
|
* @param string $type DBMS type
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace OC\DB;
|
||||||
|
|
||||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||||
use Doctrine\DBAL\Schema\SchemaConfig;
|
use Doctrine\DBAL\Schema\SchemaConfig;
|
||||||
|
use Doctrine\DBAL\Platforms\MySqlPlatform;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
|
|
||||||
class MDB2SchemaReader {
|
class MDB2SchemaReader {
|
||||||
|
@ -54,12 +55,16 @@ class MDB2SchemaReader {
|
||||||
/** @var \Doctrine\DBAL\Schema\SchemaConfig $schemaConfig */
|
/** @var \Doctrine\DBAL\Schema\SchemaConfig $schemaConfig */
|
||||||
protected $schemaConfig;
|
protected $schemaConfig;
|
||||||
|
|
||||||
|
/** @var IConfig */
|
||||||
|
protected $config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \OCP\IConfig $config
|
* @param \OCP\IConfig $config
|
||||||
* @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
|
* @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
|
||||||
*/
|
*/
|
||||||
public function __construct(IConfig $config, AbstractPlatform $platform) {
|
public function __construct(IConfig $config, AbstractPlatform $platform) {
|
||||||
$this->platform = $platform;
|
$this->platform = $platform;
|
||||||
|
$this->config = $config;
|
||||||
$this->DBNAME = $config->getSystemValue('dbname', 'owncloud');
|
$this->DBNAME = $config->getSystemValue('dbname', 'owncloud');
|
||||||
$this->DBTABLEPREFIX = $config->getSystemValue('dbtableprefix', 'oc_');
|
$this->DBTABLEPREFIX = $config->getSystemValue('dbtableprefix', 'oc_');
|
||||||
|
|
||||||
|
@ -118,8 +123,15 @@ class MDB2SchemaReader {
|
||||||
$name = str_replace('*dbprefix*', $this->DBTABLEPREFIX, $name);
|
$name = str_replace('*dbprefix*', $this->DBTABLEPREFIX, $name);
|
||||||
$name = $this->platform->quoteIdentifier($name);
|
$name = $this->platform->quoteIdentifier($name);
|
||||||
$table = $schema->createTable($name);
|
$table = $schema->createTable($name);
|
||||||
$table->addOption('collate', 'utf8_bin');
|
|
||||||
$table->setSchemaConfig($this->schemaConfig);
|
$table->setSchemaConfig($this->schemaConfig);
|
||||||
|
|
||||||
|
if($this->platform instanceof MySqlPlatform && $this->config->getSystemValue('mysql.utf8mb4', false)) {
|
||||||
|
$table->addOption('charset', 'utf8mb4');
|
||||||
|
$table->addOption('collate', 'utf8mb4_bin');
|
||||||
|
$table->addOption('row_format', 'compressed');
|
||||||
|
} else {
|
||||||
|
$table->addOption('collate', 'utf8_bin');
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'create':
|
case 'create':
|
||||||
case 'overwrite':
|
case 'overwrite':
|
||||||
|
|
|
@ -43,7 +43,11 @@ class MDB2SchemaWriter {
|
||||||
$xml->addChild('name', $config->getSystemValue('dbname', 'owncloud'));
|
$xml->addChild('name', $config->getSystemValue('dbname', 'owncloud'));
|
||||||
$xml->addChild('create', 'true');
|
$xml->addChild('create', 'true');
|
||||||
$xml->addChild('overwrite', 'false');
|
$xml->addChild('overwrite', 'false');
|
||||||
$xml->addChild('charset', 'utf8');
|
if($config->getSystemValue('dbtype', 'sqlite') === 'mysql' && $config->getSystemValue('mysql.utf8mb4', false)) {
|
||||||
|
$xml->addChild('charset', 'utf8mb4');
|
||||||
|
} else {
|
||||||
|
$xml->addChild('charset', 'utf8');
|
||||||
|
}
|
||||||
|
|
||||||
// FIX ME: bloody work around
|
// FIX ME: bloody work around
|
||||||
if ($config->getSystemValue('dbtype', 'sqlite') === 'oci') {
|
if ($config->getSystemValue('dbtype', 'sqlite') === 'oci') {
|
||||||
|
|
|
@ -61,10 +61,12 @@ class Collation implements IRepairStep {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$characterSet = $this->config->getSystemValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
|
||||||
|
|
||||||
$tables = $this->getAllNonUTF8BinTables($this->connection);
|
$tables = $this->getAllNonUTF8BinTables($this->connection);
|
||||||
foreach ($tables as $table) {
|
foreach ($tables as $table) {
|
||||||
$output->info("Change collation for $table ...");
|
$output->info("Change collation for $table ...");
|
||||||
$query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;');
|
$query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET ' . $characterSet . ' COLLATE ' . $characterSet . '_bin;');
|
||||||
$query->execute();
|
$query->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,11 +77,12 @@ class Collation implements IRepairStep {
|
||||||
*/
|
*/
|
||||||
protected function getAllNonUTF8BinTables($connection) {
|
protected function getAllNonUTF8BinTables($connection) {
|
||||||
$dbName = $this->config->getSystemValue("dbname");
|
$dbName = $this->config->getSystemValue("dbname");
|
||||||
|
$characterSet = $this->config->getSystemValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
|
||||||
$rows = $connection->fetchAll(
|
$rows = $connection->fetchAll(
|
||||||
"SELECT DISTINCT(TABLE_NAME) AS `table`" .
|
"SELECT DISTINCT(TABLE_NAME) AS `table`" .
|
||||||
" FROM INFORMATION_SCHEMA . COLUMNS" .
|
" FROM INFORMATION_SCHEMA . COLUMNS" .
|
||||||
" WHERE TABLE_SCHEMA = ?" .
|
" WHERE TABLE_SCHEMA = ?" .
|
||||||
" AND (COLLATION_NAME <> 'utf8_bin' OR CHARACTER_SET_NAME <> 'utf8')" .
|
" AND (COLLATION_NAME <> '" . $characterSet . "_bin' OR CHARACTER_SET_NAME <> '" . $characterSet . "')" .
|
||||||
" AND TABLE_NAME LIKE \"*PREFIX*%\"",
|
" AND TABLE_NAME LIKE \"*PREFIX*%\"",
|
||||||
array($dbName)
|
array($dbName)
|
||||||
);
|
);
|
||||||
|
|
|
@ -407,8 +407,8 @@ class Server extends ServerContainer implements IServerContainer {
|
||||||
return new CredentialsManager($c->getCrypto(), $c->getDatabaseConnection());
|
return new CredentialsManager($c->getCrypto(), $c->getDatabaseConnection());
|
||||||
});
|
});
|
||||||
$this->registerService('DatabaseConnection', function (Server $c) {
|
$this->registerService('DatabaseConnection', function (Server $c) {
|
||||||
$factory = new \OC\DB\ConnectionFactory();
|
|
||||||
$systemConfig = $c->getSystemConfig();
|
$systemConfig = $c->getSystemConfig();
|
||||||
|
$factory = new \OC\DB\ConnectionFactory($systemConfig);
|
||||||
$type = $systemConfig->getValue('dbtype', 'sqlite');
|
$type = $systemConfig->getValue('dbtype', 'sqlite');
|
||||||
if (!$factory->isValidType($type)) {
|
if (!$factory->isValidType($type)) {
|
||||||
throw new \OC\DatabaseException('Invalid database type');
|
throw new \OC\DatabaseException('Invalid database type');
|
||||||
|
|
|
@ -58,8 +58,9 @@ class MySQL extends AbstractDatabase {
|
||||||
try{
|
try{
|
||||||
$name = $this->dbName;
|
$name = $this->dbName;
|
||||||
$user = $this->dbUser;
|
$user = $this->dbUser;
|
||||||
//we can't use OC_BD functions here because we need to connect as the administrative user.
|
//we can't use OC_DB functions here because we need to connect as the administrative user.
|
||||||
$query = "CREATE DATABASE IF NOT EXISTS `$name` CHARACTER SET utf8 COLLATE utf8_bin;";
|
$characterSet = \OC::$server->getSystemConfig()->getValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
|
||||||
|
$query = "CREATE DATABASE IF NOT EXISTS `$name` CHARACTER SET $characterSet COLLATE ${characterSet}_bin;";
|
||||||
$connection->executeUpdate($query);
|
$connection->executeUpdate($query);
|
||||||
} catch (\Exception $ex) {
|
} catch (\Exception $ex) {
|
||||||
$this->logger->error('Database creation failed: {error}', [
|
$this->logger->error('Database creation failed: {error}', [
|
||||||
|
|
Loading…
Reference in New Issue