* fully optional * requires additional options set in the databasetags/v11.0RC2
*/ | */ | ||||
'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. | ||||
* | * |
$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())); |
} | } | ||||
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; | ||||
} | } | ||||
} | } |
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 |
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': |
$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') { |
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) | ||||
); | ); |
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'); |
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}', [ |