Quellcode durchsuchen

Add config option to update charset of mysql to utf8mb4

* fully optional
* requires additional options set in the database
tags/v11.0RC2
Morris Jobke vor 9 Jahren
Ursprung
Commit
cc28f82b36
Es ist kein Account mit der E-Mail-Adresse des Committers verbunden

+ 29
- 0
config/config.sample.php Datei anzeigen

*/ */
'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
*/ */
'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.
* *

+ 1
- 1
core/register_command.php Datei anzeigen

$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()));

+ 2
- 1
lib/private/DB/AdapterMySQL.php Datei anzeigen

} }


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;
} }
} }

+ 7
- 0
lib/private/DB/ConnectionFactory.php Datei anzeigen

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.
), ),
); );


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

+ 13
- 1
lib/private/DB/MDB2SchemaReader.php Datei anzeigen



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 {
/** @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_');


$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':

+ 5
- 1
lib/private/DB/MDB2SchemaWriter.php Datei anzeigen

$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') {

+ 5
- 2
lib/private/Repair/Collation.php Datei anzeigen

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();
} }
} }
*/ */
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)
); );

+ 1
- 1
lib/private/Server.php Datei anzeigen

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');

+ 3
- 2
lib/private/Setup/MySQL.php Datei anzeigen

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.
$query = "CREATE DATABASE IF NOT EXISTS `$name` CHARACTER SET utf8 COLLATE utf8_bin;";
//we can't use OC_DB functions here because we need to connect as the administrative user.
$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}', [

Laden…
Abbrechen
Speichern