From b8d555f56a52664f3b87016cfa0c2ff9147602b5 Mon Sep 17 00:00:00 2001 From: Tristan Darricau <tristan.darricau@gmail.com> Date: Tue, 9 Nov 2021 03:53:52 +0100 Subject: [PATCH] [ticket/16741] Specific DBs fixes MSSQL: - Fix bool type - Fix comparator - Drop Default constraint before deleting column - Rename Default constraint to use phpBB's names - Re-create the indices when changing the type of one column - Uses varchar instead of varbinary PostgreSQL: - Creates auto increment sequences by hand instead of using serial in order to use phpBB's names - Drop constraint on unique / primary indices Oracle: - Rename indices to use phpBB's names - Fix string not null behaviour - Fix broken regex in Oracle driver - Handle to long indices on Oracle - Rename auto_increment trigger and sequence - Automatically lowercase keys in assoc results PHPBB3-16741 --- .../config/default/container/services_db.yml | 2 +- .../install/convert/controller/convertor.php | 2 +- phpBB/phpbb/db/doctrine/comparator.php | 64 +++++++ phpBB/phpbb/db/doctrine/oci8/connection.php | 99 ++++++++++ phpBB/phpbb/db/doctrine/oci8/driver.php | 65 +++++++ phpBB/phpbb/db/doctrine/oci8/result.php | 109 +++++++++++ .../phpbb/db/doctrine/oci8/schema_manager.php | 45 +++++ phpBB/phpbb/db/doctrine/oci8/statement.php | 58 ++++++ phpBB/phpbb/db/doctrine/oracle_platform.php | 132 +++++++++++++ .../phpbb/db/doctrine/postgresql_platform.php | 178 ++++++++++++++++++ phpBB/phpbb/db/doctrine/sqlsrv_platform.php | 139 ++++++++++++++ phpBB/phpbb/db/driver/oracle.php | 16 +- phpBB/phpbb/db/tools/mssql.php | 2 +- phpBB/phpbb/db/tools/postgres.php | 2 +- 14 files changed, 901 insertions(+), 12 deletions(-) create mode 100644 phpBB/phpbb/db/doctrine/comparator.php create mode 100644 phpBB/phpbb/db/doctrine/oci8/connection.php create mode 100644 phpBB/phpbb/db/doctrine/oci8/driver.php create mode 100644 phpBB/phpbb/db/doctrine/oci8/result.php create mode 100644 phpBB/phpbb/db/doctrine/oci8/schema_manager.php create mode 100644 phpBB/phpbb/db/doctrine/oci8/statement.php create mode 100644 phpBB/phpbb/db/doctrine/postgresql_platform.php create mode 100644 phpBB/phpbb/db/doctrine/sqlsrv_platform.php diff --git a/phpBB/config/default/container/services_db.yml b/phpBB/config/default/container/services_db.yml index 4b0e49dddb..bad99b7d87 100644 --- a/phpBB/config/default/container/services_db.yml +++ b/phpBB/config/default/container/services_db.yml @@ -10,7 +10,7 @@ services: dbal.conn.doctrine: synthetic: true - # ----- DB Tools ----- +# ----- DB Tools ----- dbal.tools.factory: class: phpbb\db\tools\factory diff --git a/phpBB/install/convert/controller/convertor.php b/phpBB/install/convert/controller/convertor.php index aa388204cd..6c95c7dc1a 100644 --- a/phpBB/install/convert/controller/convertor.php +++ b/phpBB/install/convert/controller/convertor.php @@ -13,6 +13,7 @@ namespace phpbb\convert\controller; +use Doctrine\DBAL\Connection; use phpbb\cache\driver\driver_interface; use phpbb\db\doctrine\connection_factory; use phpbb\exception\http_exception; @@ -26,7 +27,6 @@ use phpbb\install\helper\navigation\navigation_provider; use phpbb\language\language; use phpbb\request\request_interface; use phpbb\template\template; -use PHPUnit\DbUnit\Database\Connection; use Symfony\Component\HttpFoundation\StreamedResponse; /** diff --git a/phpBB/phpbb/db/doctrine/comparator.php b/phpBB/phpbb/db/doctrine/comparator.php new file mode 100644 index 0000000000..27390e3da0 --- /dev/null +++ b/phpBB/phpbb/db/doctrine/comparator.php @@ -0,0 +1,64 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\doctrine; + +use Doctrine\DBAL\Schema\Table; + +class comparator extends \Doctrine\DBAL\Schema\Comparator +{ + /** + * {@inerhitDoc} + */ + public function diffTable(Table $fromTable, Table $toTable) + { + $diff = parent::diffTable($fromTable, $toTable); + + if ($diff === false) + { + return $diff; + } + + if (!is_array($diff->changedColumns)) + { + return $diff; + } + + // When the type of a column changes, re-create the associated indices + foreach ($diff->changedColumns as $columnName => $changedColumn) + { + if (!$changedColumn->hasChanged('type')) + { + continue; + } + + foreach ($toTable->getIndexes() as $index_name => $index) + { + if (array_key_exists($index_name, $diff->addedIndexes) || array_key_exists($index_name, $diff->changedIndexes)) + { + continue; + } + + $index_columns = array_map('strtolower', $index->getUnquotedColumns()); + if (array_search($columnName, $index_columns, true) === false) + { + continue; + } + + $diff->changedIndexes[$index_name] = $index; + } + } + + return $diff; + } +} diff --git a/phpBB/phpbb/db/doctrine/oci8/connection.php b/phpBB/phpbb/db/doctrine/oci8/connection.php new file mode 100644 index 0000000000..98d11c2fbe --- /dev/null +++ b/phpBB/phpbb/db/doctrine/oci8/connection.php @@ -0,0 +1,99 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\doctrine\oci8; + +use Doctrine\DBAL\Driver\Connection as DriverConnection; +use Doctrine\DBAL\Driver\Result as DriverResult; +use Doctrine\DBAL\Driver\Statement as DriverStatement; +use Doctrine\DBAL\ParameterType; + +class Connection implements DriverConnection +{ + /** + * @var DriverConnection + */ + private $wrapped; + + /** + * @param DriverConnection $wrapped + */ + public function __construct(DriverConnection $wrapped) + { + $this->wrapped = $wrapped; + } + + /** + * {@inheritDoc} + */ + public function prepare(string $sql): DriverStatement + { + return new statement($this->wrapped->prepare($sql)); + } + + /** + * {@inheritDoc} + */ + public function query(string $sql): DriverResult + { + return new result($this->wrapped->query($sql)); + } + + /** + * {@inheritDoc} + */ + public function quote($value, $type = ParameterType::STRING) + { + return $this->wrapped->quote($value, $type); + } + + /** + * {@inheritDoc} + */ + public function exec(string $sql): int + { + return $this->wrapped->exec($sql); + } + + /** + * {@inheritDoc} + */ + public function lastInsertId($name = null) + { + return $this->wrapped->lastInsertId($name); + } + + /** + * {@inheritDoc} + */ + public function beginTransaction() + { + return $this->wrapped->beginTransaction(); + } + + /** + * {@inheritDoc} + */ + public function commit() + { + return $this->wrapped->commit(); + } + + /** + * {@inheritDoc} + */ + public function rollBack() + { + return $this->wrapped->rollBack(); + } +} diff --git a/phpBB/phpbb/db/doctrine/oci8/driver.php b/phpBB/phpbb/db/doctrine/oci8/driver.php new file mode 100644 index 0000000000..0a5300092c --- /dev/null +++ b/phpBB/phpbb/db/doctrine/oci8/driver.php @@ -0,0 +1,65 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\doctrine\oci8; + +use Doctrine\DBAL\Connection as DoctrineConnection; +use Doctrine\DBAL\Driver\API\ExceptionConverter; +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Driver as DoctrineDriver; +use Doctrine\DBAL\Driver\OCI8\Driver as OCI8Driver; + +class driver implements DoctrineDriver +{ + /** + * @var DoctrineDriver + */ + private $wrapped; + + public function __construct() + { + $this->wrapped = new OCI8Driver(); + } + + /** + * {@inheritDoc} + */ + public function connect(array $params) + { + return new connection($this->wrapped->connect($params)); + } + + /** + * {@inheritDoc} + */ + public function getDatabasePlatform() + { + return $this->wrapped->getDatabasePlatform(); + } + + /** + * {@inheritDoc} + */ + public function getSchemaManager(DoctrineConnection $conn, AbstractPlatform $platform) + { + return new schema_manager($conn, $platform); + } + + /** + * {@inheritDoc} + */ + public function getExceptionConverter(): ExceptionConverter + { + return $this->wrapped->getExceptionConverter(); + } +} diff --git a/phpBB/phpbb/db/doctrine/oci8/result.php b/phpBB/phpbb/db/doctrine/oci8/result.php new file mode 100644 index 0000000000..60072bfe9f --- /dev/null +++ b/phpBB/phpbb/db/doctrine/oci8/result.php @@ -0,0 +1,109 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\doctrine\oci8; + +use Doctrine\DBAL\Driver\Result as DriverResult; + +class result implements DriverResult +{ + /** + * @var DriverResult + */ + private $wrapped; + + /** + * @param DriverResult $wrapped + */ + public function __construct(DriverResult $wrapped) + { + $this->wrapped = $wrapped; + } + + /** + * {@inheritDoc} + */ + public function fetchNumeric() + { + return $this->wrapped->fetchNumeric(); + } + + /** + * {@inheritDoc} + */ + public function fetchAssociative() + { + return array_change_key_case($this->wrapped->fetchAssociative(), CASE_LOWER); + } + + /** + * {@inheritDoc} + */ + public function fetchOne() + { + return $this->wrapped->fetchOne(); + } + + /** + * {@inheritDoc} + */ + public function fetchAllNumeric(): array + { + return $this->wrapped->fetchAllNumeric(); + } + + /** + * {@inheritDoc} + */ + public function fetchAllAssociative(): array + { + $rows = []; + foreach ($this->wrapped->fetchAllAssociative() as $row) + { + $rows[] = array_change_key_case($row, CASE_LOWER); + } + return $rows; + } + + /** + * {@inheritDoc} + */ + public function fetchFirstColumn(): array + { + return $this->wrapped->fetchFirstColumn(); + } + + /** + * {@inheritDoc} + */ + public function rowCount(): int + { + return $this->wrapped->rowCount(); + } + + /** + * {@inheritDoc} + */ + public function columnCount(): int + { + return $this->wrapped->columnCount(); + } + + /** + * {@inheritDoc} + */ + public function free(): void + { + $this->wrapped->free(); + } +} diff --git a/phpBB/phpbb/db/doctrine/oci8/schema_manager.php b/phpBB/phpbb/db/doctrine/oci8/schema_manager.php new file mode 100644 index 0000000000..aeb1120e12 --- /dev/null +++ b/phpBB/phpbb/db/doctrine/oci8/schema_manager.php @@ -0,0 +1,45 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\doctrine\oci8; + +use Doctrine\DBAL\Platforms\OraclePlatform; +use Doctrine\DBAL\Schema\AbstractSchemaManager; +use Doctrine\DBAL\Schema\OracleSchemaManager; +use Doctrine\DBAL\Schema\Table; + +class schema_manager extends OracleSchemaManager +{ + /** + * {@inheritdoc} + * + * Copied from upstream to lowercase 'COMMENTS' + */ + public function listTableDetails($name): Table + { + $table = AbstractSchemaManager::listTableDetails($name); + + $platform = $this->_platform; + assert($platform instanceof OraclePlatform); + $sql = $platform->getListTableCommentsSQL($name); + + $tableOptions = $this->_conn->fetchAssociative($sql); + + if ($tableOptions !== false) + { + $table->addOption('comment', $tableOptions['comments']); + } + + return $table; + } +} diff --git a/phpBB/phpbb/db/doctrine/oci8/statement.php b/phpBB/phpbb/db/doctrine/oci8/statement.php new file mode 100644 index 0000000000..332c3fab32 --- /dev/null +++ b/phpBB/phpbb/db/doctrine/oci8/statement.php @@ -0,0 +1,58 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\doctrine\oci8; + +use Doctrine\DBAL\Driver\Result as DriverResult; +use Doctrine\DBAL\Driver\Statement as DriverStatement; +use Doctrine\DBAL\ParameterType; + +class statement implements DriverStatement +{ + /** + * @var DriverStatement + */ + private $wrapped; + + /** + * @param DriverStatement $wrapped + */ + public function __construct(DriverStatement $wrapped) + { + $this->wrapped = $wrapped; + } + + /** + * {@inheritDoc} + */ + public function bindValue($param, $value, $type = ParameterType::STRING) + { + return $this->wrapped->bindValue($param, $value, $type); + } + + /** + * {@inheritDoc} + */ + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) + { + return $this->wrapped->bindParam($param, $variable, $type, $length); + } + + /** + * {@inheritDoc} + */ + public function execute($params = null): DriverResult + { + return new result($this->wrapped->execute($params)); + } +} diff --git a/phpBB/phpbb/db/doctrine/oracle_platform.php b/phpBB/phpbb/db/doctrine/oracle_platform.php index 6c8de23e8a..43ace17795 100644 --- a/phpBB/phpbb/db/doctrine/oracle_platform.php +++ b/phpBB/phpbb/db/doctrine/oracle_platform.php @@ -14,6 +14,9 @@ namespace phpbb\db\doctrine; use Doctrine\DBAL\Platforms\OraclePlatform; +use Doctrine\DBAL\Schema\Identifier; +use Doctrine\DBAL\Schema\Index; +use Doctrine\DBAL\Schema\Table; /** * Oracle specific schema restrictions for BC. @@ -40,4 +43,133 @@ class oracle_platform extends OraclePlatform { return parent::getVarcharTypeDeclarationSQL($column); } + + /** + * {@inheritDoc} + */ + public function getCreateIndexSQL(Index $index, $table) + { + if ($table instanceof Table) + { + $table_name = $table->getName(); + } + else + { + $table_name = $table; + } + + $index_name = $index->getName(); + if (strpos($index->getName(), $table_name) !== 0) + { + $index_name = $table_name . '_' . $index->getName(); + } + + $index = new Index( + $this->check_index_name_length($table_name, $index_name), + $index->getColumns(), + $index->isUnique(), + $index->isPrimary(), + $index->getFlags(), + $index->getOptions() + ); + + return parent::getCreateIndexSQL($index, $table); + } + + /** + * Check whether the index name is too long + * + * @param string $table_name + * @param string $index_name + * @param bool $throw_error + * @return string The index name, shortened if too long + */ + protected function check_index_name_length($table_name, $index_name, $throw_error = true) + { + $max_index_name_length = $this->getMaxIdentifierLength(); + if (strlen($index_name) > $max_index_name_length) + { + // Try removing the table prefix if it's at the beginning + $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config) + if (strpos($index_name, $table_prefix) === 0) + { + $index_name = substr($index_name, strlen($table_prefix)); + return $this->check_index_name_length($table_name, $index_name, $throw_error); + } + + // Try removing the remaining suffix part of table name then + $table_suffix = substr($table_name, strlen($table_prefix)); + if (strpos($index_name, $table_suffix) === 0) + { + // Remove the suffix and underscore separator between table_name and index_name + $index_name = substr($index_name, strlen($table_suffix) + 1); + return $this->check_index_name_length($table_name, $index_name, $throw_error); + } + + if ($throw_error) + { + trigger_error("Index name '$index_name' on table '$table_name' is too long. The maximum is $max_index_name_length characters.", E_USER_ERROR); + } + } + + return $index_name; + } + + /** + * {@inheritdoc} + */ + public function getIdentitySequenceName($tableName, $columnName) + { + return $tableName.'_SEQ'; + } + + /** + * {@inheritDoc} + */ + public function getCreateAutoincrementSql($name, $table, $start = 1) + { + $sql = parent::getCreateAutoincrementSql($name, $table, $start); + + return str_replace( + $this->get_doctrine_autoincrement_identifier_name($this->doctrine_normalize_identifier($table)), + 'T_'.$table, + $sql + ); + } + + /** + * @see OraclePlatform::normalizeIdentifier() + */ + private function doctrine_normalize_identifier($name) + { + $identifier = new Identifier($name); + + return $identifier->isQuoted() ? $identifier : new Identifier(strtoupper($name)); + } + + /** + * @see OraclePlatform::getAutoincrementIdentifierName() + */ + private function get_doctrine_autoincrement_identifier_name(Identifier $table) + { + $identifierName = $this->add_doctrine_Suffix($table->getName(), '_AI_PK'); + + return $table->isQuoted() + ? $this->quoteSingleIdentifier($identifierName) + : $identifierName; + } + + /** + * @see OraclePlatform::addSuffix() + */ + private function add_doctrine_Suffix(string $identifier, string $suffix): string + { + $maxPossibleLengthWithoutSuffix = $this->getMaxIdentifierLength() - strlen($suffix); + if (strlen($identifier) > $maxPossibleLengthWithoutSuffix) + { + $identifier = substr($identifier, 0, $maxPossibleLengthWithoutSuffix); + } + + return $identifier . $suffix; + } } diff --git a/phpBB/phpbb/db/doctrine/postgresql_platform.php b/phpBB/phpbb/db/doctrine/postgresql_platform.php new file mode 100644 index 0000000000..197f9ac386 --- /dev/null +++ b/phpBB/phpbb/db/doctrine/postgresql_platform.php @@ -0,0 +1,178 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\doctrine; + +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Platforms\PostgreSQL94Platform; +use Doctrine\DBAL\Schema\Index; +use Doctrine\DBAL\Schema\Sequence; +use Doctrine\DBAL\Schema\Table; +use Doctrine\DBAL\Types\BigIntType; +use Doctrine\DBAL\Types\IntegerType; +use Doctrine\DBAL\Types\SmallIntType; +use Doctrine\DBAL\Types\Type; + +/** + * PostgreSQL specific schema restrictions for BC. + * + * Doctrine is using SERIAL which auto creates the sequences with + * a name different from the one our driver is using. So in order + * to stay compatible with the existing DB we have to change its + * naming and not ours. + */ +class postgresql_platform extends PostgreSQL94Platform +{ + /** + * {@inheritdoc} + */ + public function getIdentitySequenceName($tableName, $columnName) + { + return $tableName . '_seq'; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $column) + { + return 'INT'; + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $column) + { + return 'BIGINT'; + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $column) + { + return 'SMALLINT'; + } + + /** + * {@inheritDoc} + */ + public function getDefaultValueDeclarationSQL($column) + { + if ($this->isSerialColumn($column)) + { + return ' DEFAULT {{placeholder_sequence}}'; + } + + return AbstractPlatform::getDefaultValueDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function supportsIdentityColumns() + { + return false; + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($name, array $columns, array $options = []) + { + $sql = []; + $post_sql = []; + foreach ($columns as $column_name => $column) + { + if (! empty($column['autoincrement'])) + { + $sequence = new Sequence($this->getIdentitySequenceName($name, $column_name)); + $sql[] = $this->getCreateSequenceSQL($sequence); + $post_sql[] = 'ALTER SEQUENCE '.$sequence->getName().' OWNED BY '.$name.'.'.$column_name; + } + } + $sql = array_merge($sql, parent::_getCreateTableSQL($name, $columns, $options), $post_sql); + + foreach ($sql as $i => $query) + { + $sql[$i] = str_replace('{{placeholder_sequence}}', "nextval('{$name}_seq')", $query); + } + + return $sql; + } + + /** + * @param mixed[] $column + */ + private function isSerialColumn(array $column): bool + { + return isset($column['type'], $column['autoincrement']) + && $column['autoincrement'] === true + && $this->isNumericType($column['type']); + } + + private function isNumericType(Type $type): bool + { + return $type instanceof IntegerType || $type instanceof BigIntType || $type instanceof SmallIntType; + } + + /** + * {@inheritDoc} + */ + public function getListSequencesSQL($database) + { + return "SELECT sequence_name AS relname, + sequence_schema AS schemaname, + 1 AS min_value, + 1 AS increment_by + FROM information_schema.sequences + WHERE sequence_schema NOT LIKE 'pg\_%' + AND sequence_schema != 'information_schema'"; + } + + /** + * {@inheritDoc} + */ + public function getDropIndexSQL($index, $table = null) + { + // If we have a primary or a unique index, we need to drop the constraint + // instead of the index itself or postgreSQL will reject the query. + if ($index instanceof Index) + { + if ($index->isPrimary()) + { + if ($table instanceof Table) + { + $table = $table->getQuotedName($this); + } + else if (!is_string($table)) + { + throw new \InvalidArgumentException( + __METHOD__ . '() expects $table parameter to be string or ' . Table::class . '.' + ); + } + + return 'ALTER TABLE '.$table.' DROP CONSTRAINT '.$index->getQuotedName($this); + } + } + else if (! is_string($index)) + { + throw new \InvalidArgumentException( + __METHOD__ . '() expects $index parameter to be string or ' . Index::class . '.' + ); + } + + return parent::getDropIndexSQL($index, $table); + } +} diff --git a/phpBB/phpbb/db/doctrine/sqlsrv_platform.php b/phpBB/phpbb/db/doctrine/sqlsrv_platform.php new file mode 100644 index 0000000000..58deed2423 --- /dev/null +++ b/phpBB/phpbb/db/doctrine/sqlsrv_platform.php @@ -0,0 +1,139 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\doctrine; + +use Doctrine\DBAL\Platforms\SQLServer2012Platform; +use Doctrine\DBAL\Schema\Identifier; +use Doctrine\DBAL\Schema\TableDiff; + +/** + * Oracle specific schema restrictions for BC. + */ +class sqlsrv_platform extends SQLServer2012Platform +{ + /** + * {@inheritDoc} + * + * Renames the default constraints to use the classic phpBB's names + */ + public function getDefaultConstraintDeclarationSQL($table, array $column) + { + $sql = parent::getDefaultConstraintDeclarationSQL($table, $column); + + return str_replace( + [ + $this->generate_doctrine_identifier_name($table), + $this->generate_doctrine_identifier_name($column['name']), + ], [ + $table, + $column['name'].'_1', + ], + $sql); + } + + /** + * {@inheritDoc} + * + * Renames the default constraints to use the classic phpBB's names + */ + public function getAlterTableSQL(TableDiff $diff) + { + $sql = []; + + // When dropping a column, if it has a default we need to drop the default constraint first + foreach ($diff->removedColumns as $column) + { + if (!$column->getAutoincrement()) + { + $sql[] = $this->getDropConstraintSQL($this->generate_doctrine_default_constraint_name($diff->name, $column->getQuotedName($this)), $diff->name); + } + } + + $sql = array_merge($sql, parent::getAlterTableSQL($diff)); + + $doctrine_names = []; + $phpbb_names = []; + + // OLD Table name + $doctrine_names[] = $this->generate_doctrine_identifier_name($diff->name); + $phpbb_names[] = $diff->name; + + // NEW Table name if relevant + if ($diff->getNewName() != null) + { + $doctrine_names[] = $this->generate_doctrine_identifier_name($diff->getNewName()->getName()); + $phpbb_names[] = $diff->getNewName()->getName(); + } + + foreach ($diff->addedColumns as $column) + { + $doctrine_names[] = $this->generate_doctrine_identifier_name($column->getQuotedName($this)); + $phpbb_names[] = $column->getQuotedName($this).'_1'; + } + + foreach ($diff->removedColumns as $column) + { + $doctrine_names[] = $this->generate_doctrine_identifier_name($column->getQuotedName($this)); + $phpbb_names[] = $column->getQuotedName($this).'_1'; + } + + foreach ($diff->renamedColumns as $column) + { + $doctrine_names[] = $this->generate_doctrine_identifier_name($column->getQuotedName($this)); + $phpbb_names[] = $column->getQuotedName($this).'_1'; + } + + foreach ($diff->changedColumns as $column) + { + $doctrine_names[] = $this->generate_doctrine_identifier_name($column->column->getQuotedName($this)); + $phpbb_names[] = $column->column->getQuotedName($this).'_1'; + + if ($column->oldColumnName != $column->column->getQuotedName($this)) + { + $doctrine_names[] = $this->generate_doctrine_identifier_name($column->oldColumnName); + $phpbb_names[] = $column->oldColumnName.'_1'; + } + } + + return str_replace($doctrine_names, $phpbb_names, $sql); + } + + /** + * Returns a hash value for a given identifier. + * + * @param string $identifier Identifier to generate a hash value for. + * + * @return string + */ + private function generate_doctrine_identifier_name($identifier) + { + // Always generate name for unquoted identifiers to ensure consistency. + $identifier = new Identifier($identifier); + + return strtoupper(dechex(crc32($identifier->getName()))); + } + + /** + * Returns a unique default constraint name for a table and column. + * + * @param string $table Name of the table to generate the unique default constraint name for. + * @param string $column Name of the column in the table to generate the unique default constraint name for. + * + * @return string + */ + private function generate_doctrine_default_constraint_name($table, $column) + { + return 'DF_' . $this->generate_doctrine_identifier_name($table) . '_' . $this->generate_doctrine_identifier_name($column); + } +} diff --git a/phpBB/phpbb/db/driver/oracle.php b/phpBB/phpbb/db/driver/oracle.php index 3f6bc49b35..04af0a0a9c 100644 --- a/phpBB/phpbb/db/driver/oracle.php +++ b/phpBB/phpbb/db/driver/oracle.php @@ -160,7 +160,7 @@ class oracle extends \phpbb\db\driver\driver */ function _rewrite_where($where_clause) { - preg_match_all('/\s*(AND|OR)?\s*([\w_.()]++)\s*(?:(=|<[=>]?|>=?|LIKE)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d-.()]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER); + preg_match_all('/\s*(AND|OR)?\s*([\w_.()]++)\s*(?:(=|<[=>]?|>=?|LIKE)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d\-.()]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d\-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER); $out = ''; foreach ($result as $val) { @@ -188,7 +188,7 @@ class oracle extends \phpbb\db\driver\driver $in_clause = array(); $sub_exp = substr($val[5], strpos($val[5], '(') + 1, -1); $extra = false; - preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER); + preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d\-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER); $i = 0; foreach ($sub_vals[0] as $sub_val) { @@ -282,7 +282,7 @@ class oracle extends \phpbb\db\driver\driver { $cols = explode(', ', $regs[2]); - preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER); + preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d\-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER); /* The code inside this comment block breaks clob handling, but does allow the database restore script to work. If you want to allow no posts longer than 4KB @@ -353,13 +353,13 @@ class oracle extends \phpbb\db\driver\driver $query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')'; } } - else if (preg_match_all('/^(UPDATE [\\w_]++\\s+SET )([\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+)(?:,\\s*[\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+)\\s+(WHERE.*)$/s', $query, $data, PREG_SET_ORDER)) + else if (preg_match_all('/^(UPDATE [\\w_]++\\s+SET )([\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d\-.]+)(?:,\\s*[\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d\-.]+))*+)\\s+(WHERE.*)$/s', $query, $data, PREG_SET_ORDER)) { if (strlen($data[0][2]) > 4000) { $update = $data[0][1]; $where = $data[0][3]; - preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[0][2], $temp, PREG_SET_ORDER); + preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d\-.]++)/', $data[0][2], $temp, PREG_SET_ORDER); unset($data); $cols = array(); @@ -385,7 +385,7 @@ class oracle extends \phpbb\db\driver\driver switch (substr($query, 0, 6)) { case 'DELETE': - if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))*+)$/', $query, $regs)) + if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d\-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d\-.]+,? ?)*+\)))*+)$/', $query, $regs)) { $query = $regs[1] . $this->_rewrite_where($regs[2]); unset($regs); @@ -393,7 +393,7 @@ class oracle extends \phpbb\db\driver\driver break; case 'UPDATE': - if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++))*+\\s+WHERE)(.*)$/s', $query, $regs)) + if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d\-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d\-.]++|:\w++))*+\\s+WHERE)(.*)$/s', $query, $regs)) { $query = $regs[1] . $this->_rewrite_where($regs[2]); unset($regs); @@ -401,7 +401,7 @@ class oracle extends \phpbb\db\driver\driver break; case 'SELECT': - $query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query); + $query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d\-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d\-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query); break; } diff --git a/phpBB/phpbb/db/tools/mssql.php b/phpBB/phpbb/db/tools/mssql.php index b638e9faaf..58d2dde045 100644 --- a/phpBB/phpbb/db/tools/mssql.php +++ b/phpBB/phpbb/db/tools/mssql.php @@ -19,6 +19,6 @@ namespace phpbb\db\tools; * * @deprecated 4.0.0-a1 */ -class mssql extends tools +class mssql extends doctrine { } diff --git a/phpBB/phpbb/db/tools/postgres.php b/phpBB/phpbb/db/tools/postgres.php index 1beac0bb6b..611c3ebf0f 100644 --- a/phpBB/phpbb/db/tools/postgres.php +++ b/phpBB/phpbb/db/tools/postgres.php @@ -19,6 +19,6 @@ namespace phpbb\db\tools; * * @deprecated 4.0.0-a1 */ -class postgres extends tools +class postgres extends doctrine { }