From a3bdb318e9f552f342de401d0aff24384a80fcd8 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 29 Sep 2017 11:07:50 +0200 Subject: Fix bigint handling on postgres Signed-off-by: Joas Schilling --- lib/private/DB/ConnectionFactory.php | 4 ++ lib/private/DB/OCPostgreSqlPlatform.php | 94 +++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 lib/private/DB/OCPostgreSqlPlatform.php (limited to 'lib/private') diff --git a/lib/private/DB/ConnectionFactory.php b/lib/private/DB/ConnectionFactory.php index d90d7737d40..8848f6db3b4 100644 --- a/lib/private/DB/ConnectionFactory.php +++ b/lib/private/DB/ConnectionFactory.php @@ -137,6 +137,10 @@ class ConnectionFactory { } unset($additionalConnectionParams['host']); break; + + case 'pgsql': + $additionalConnectionParams['platform'] = new OCPostgreSqlPlatform(); + break; case 'sqlite3': $journalMode = $additionalConnectionParams['sqlite.journal_mode']; $additionalConnectionParams['platform'] = new OCSqlitePlatform(); diff --git a/lib/private/DB/OCPostgreSqlPlatform.php b/lib/private/DB/OCPostgreSqlPlatform.php new file mode 100644 index 00000000000..524a62c2beb --- /dev/null +++ b/lib/private/DB/OCPostgreSqlPlatform.php @@ -0,0 +1,94 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\DB; + +use Doctrine\DBAL\Platforms\PostgreSqlPlatform; +use Doctrine\DBAL\Schema\ColumnDiff; +use Doctrine\DBAL\Schema\TableDiff; +use Doctrine\DBAL\Types\Type; + +class OCPostgreSqlPlatform extends PostgreSqlPlatform { + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff){ + $queries = parent::getAlterTableSQL($diff); + foreach ($queries as $index => $sql){ + // BIGSERIAL could not be used in statements altering column type + // That's why we replace it with BIGINT + // see https://github.com/owncloud/core/pull/28364#issuecomment-315006853 + if (preg_match('|(ALTER TABLE\s+\S+\s+ALTER\s+\S+\s+TYPE\s+)(BIGSERIAL)|i', $sql, $matches)) { + $alterTable = $matches[1]; + $queries[$index] = $alterTable . 'BIGINT'; + } + + // Changing integer to bigint kills next autoincrement value + // see https://github.com/owncloud/core/pull/28364#issuecomment-315006853 + if (preg_match('|ALTER TABLE\s+(\S+)\s+ALTER\s+(\S+)\s+DROP DEFAULT|i', $sql, $matches)) { + $queryColumnName = $matches[2]; + $columnDiff = $this->findColumnDiffByName($diff, $queryColumnName); + if ($columnDiff && $this->shouldSkipDropDefault($columnDiff)) { + unset($queries[$index]); + continue; + } + } + } + + return $queries; + } + + /** + * We should NOT drop next sequence value if + * - type was changed from INTEGER to BIGINT + * - column keeps an autoincrement + * - default value is kept NULL + * + * @param ColumnDiff $columnDiff + * @return bool + */ + private function shouldSkipDropDefault(ColumnDiff $columnDiff) { + $column = $columnDiff->column; + $fromColumn = $columnDiff->fromColumn; + return $fromColumn->getType()->getName() === Type::INTEGER + && $column->getType()->getName() === Type::BIGINT + && $fromColumn->getDefault() === null + && $column->getDefault() === null + && $fromColumn->getAutoincrement() + && $column->getAutoincrement(); + } + + /** + * @param TableDiff $diff + * @param string $name + * @return ColumnDiff | false + */ + private function findColumnDiffByName(TableDiff $diff, $name) { + foreach ($diff->changedColumns as $columnDiff) { + $oldColumnName = $columnDiff->getOldColumnName()->getQuotedName($this); + if ($oldColumnName === $name) { + return $columnDiff; + } + } + return false; + } +} -- cgit v1.2.3