owncloud/core

View on GitHub
lib/private/DB/OracleMigrator.php

Summary

Maintainability
C
7 hrs
Test Coverage
<?php
/**
 * @author Morris Jobke <hey@morrisjobke.de>
 * @author Robin Appelman <icewind@owncloud.com>
 * @author Thomas Müller <thomas.mueller@tmit.eu>
 *
 * @copyright Copyright (c) 2018, 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 <http://www.gnu.org/licenses/>
 *
 */

namespace OC\DB;

use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\ColumnDiff;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;

class OracleMigrator extends Migrator {
    /**
     * Quote a column's name but changing the name requires recreating
     * the column instance and copying over all properties.
     *
     * @param Column $column old column
     * @return Column new column instance with new name
     */
    protected function quoteColumn($column) {
        $newColumn = new Column(
            $this->connection->quoteIdentifier($column->getName()),
            $column->getType()
        );
        $newColumn->setAutoincrement($column->getAutoincrement());
        $newColumn->setColumnDefinition($column->getColumnDefinition());
        $newColumn->setComment($column->getComment());
        $newColumn->setDefault($column->getDefault());
        $newColumn->setFixed($column->getFixed());
        $newColumn->setLength($column->getLength());
        $newColumn->setNotnull($column->getNotnull());
        $newColumn->setPrecision($column->getPrecision());
        $newColumn->setScale($column->getScale());
        $newColumn->setUnsigned($column->getUnsigned());
        $newColumn->setPlatformOptions($column->getPlatformOptions());
        $newColumn->setCustomSchemaOptions($column->getPlatformOptions());
        return $newColumn;
    }

    /**
     * Quote an index's name but changing the name requires recreating
     * the index instance and copying over all properties.
     *
     * @param Index $index old index
     * @return Index new index instance with new name
     */
    protected function quoteIndex($index) {
        return new Index(
            //TODO migrate existing uppercase indexes, then $this->connection->quoteIdentifier($index->getName()),
            $index->getName(),
            \array_map(function ($columnName) {
                return $this->connection->quoteIdentifier($columnName);
            }, $index->getColumns()),
            $index->isUnique(),
            $index->isPrimary(),
            $index->getFlags(),
            $index->getOptions()
        );
    }

    /**
     * Quote an ForeignKeyConstraint's name but changing the name requires recreating
     * the ForeignKeyConstraint instance and copying over all properties.
     *
     * @param ForeignKeyConstraint $fkc old fkc
     * @return ForeignKeyConstraint new fkc instance with new name
     */
    protected function quoteForeignKeyConstraint($fkc) {
        return new ForeignKeyConstraint(
            \array_map(function ($columnName) {
                return $this->connection->quoteIdentifier($columnName);
            }, $fkc->getLocalColumns()),
            $this->connection->quoteIdentifier($fkc->getForeignTableName()),
            \array_map(function ($columnName) {
                return $this->connection->quoteIdentifier($columnName);
            }, $fkc->getForeignColumns()),
            $fkc->getName(),
            $fkc->getOptions()
        );
    }

    /**
     * @param Schema $targetSchema
     * @param \Doctrine\DBAL\Connection $connection
     * @return \Doctrine\DBAL\Schema\SchemaDiff
     */
    protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) {
        $schemaDiff = parent::getDiff($targetSchema, $connection);

        // oracle forces us to quote the identifiers
        $schemaDiff->newTables = \array_map(function (Table $table) {
            return new Table(
                $this->connection->quoteIdentifier($table->getName()),
                \array_map(function (Column $column) {
                    return $this->quoteColumn($column);
                }, $table->getColumns()),
                \array_map(function (Index $index) {
                    return $this->quoteIndex($index);
                }, $table->getIndexes()),
                \array_map(function (ForeignKeyConstraint $fck) {
                    return $this->quoteForeignKeyConstraint($fck);
                }, $table->getForeignKeys()),
                0,
                $table->getOptions()
            );
        }, $schemaDiff->newTables);

        $schemaDiff->removedTables = \array_map(function (Table $table) {
            return new Table(
                $this->connection->quoteIdentifier($table->getName()),
                $table->getColumns(),
                $table->getIndexes(),
                $table->getForeignKeys(),
                0,
                $table->getOptions()
            );
        }, $schemaDiff->removedTables);

        foreach ($schemaDiff->changedTables as $tableDiff) {
            $tableDiff->name = $this->connection->quoteIdentifier($tableDiff->name);

            $tableDiff->addedColumns = \array_map(function (Column $column) {
                return $this->quoteColumn($column);
            }, $tableDiff->addedColumns);

            foreach ($tableDiff->changedColumns as $column) {
                $column->oldColumnName = $this->connection->quoteIdentifier($column->oldColumnName);
                // auto increment is not relevant for oracle and can anyhow not be applied on change
                $column->changedProperties = \array_diff($column->changedProperties, ['autoincrement', 'unsigned']);
            }
            // remove columns that no longer have changed (because autoincrement and unsigned are not supported)
            $tableDiff->changedColumns = \array_filter($tableDiff->changedColumns, function (ColumnDiff $column) {
                return \count($column->changedProperties) > 0;
            });

            $tableDiff->removedColumns = \array_map(function (Column $column) {
                return $this->quoteColumn($column);
            }, $tableDiff->removedColumns);

            $tableDiff->renamedColumns = \array_map(function (Column $column) {
                return $this->quoteColumn($column);
            }, $tableDiff->renamedColumns);

            $tableDiff->addedIndexes = \array_map(function (Index $index) {
                return $this->quoteIndex($index);
            }, $tableDiff->addedIndexes);

            $tableDiff->changedIndexes = \array_map(function (Index $index) {
                return $this->quoteIndex($index);
            }, $tableDiff->changedIndexes);

            $tableDiff->removedIndexes = \array_map(function (Index $index) {
                return $this->quoteIndex($index);
            }, $tableDiff->removedIndexes);

            $tableDiff->renamedIndexes = \array_map(function (Index $index) {
                return $this->quoteIndex($index);
            }, $tableDiff->renamedIndexes);

            $tableDiff->addedForeignKeys = \array_map(function (ForeignKeyConstraint $fkc) {
                return $this->quoteForeignKeyConstraint($fkc);
            }, $tableDiff->addedForeignKeys);

            $tableDiff->changedForeignKeys = \array_map(function (ForeignKeyConstraint $fkc) {
                return $this->quoteForeignKeyConstraint($fkc);
            }, $tableDiff->changedForeignKeys);

            $tableDiff->removedForeignKeys = \array_map(function (ForeignKeyConstraint $fkc) {
                return $this->quoteForeignKeyConstraint($fkc);
            }, $tableDiff->removedForeignKeys);
        }

        return $schemaDiff;
    }

    /**
     * @param string $name
     * @return string
     */
    protected function generateTemporaryTableName($name) {
        return 'oc_' . \uniqid();
    }

    /**
     * @param $statement
     * @return string
     */
    protected function convertStatementToScript($statement) {
        if (\substr($statement, -1) === ';') {
            return $statement . PHP_EOL . '/' . PHP_EOL;
        }
        $script = $statement . ';';
        $script .= PHP_EOL;
        $script .= PHP_EOL;
        return $script;
    }

    protected function getFilterExpression() {
        return '/^"' . \preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/';
    }
}