From 6a51c1bc4fd0f2496103f901fef3b550688c2364 Mon Sep 17 00:00:00 2001
From: Piotr Mrowczynski <mrow4a@yahoo.com>
Date: Mon, 2 Oct 2017 12:32:21 +0200
Subject: [PATCH] Add foreign key support to OC

---
 lib/private/DB/OracleMigrator.php | 40 +++++++++++++++++++++++++++----
 tests/lib/DB/MigratorTest.php     | 39 ++++++++++++++++++++++++++++--
 2 files changed, 73 insertions(+), 6 deletions(-)

diff --git a/lib/private/DB/OracleMigrator.php b/lib/private/DB/OracleMigrator.php
index b01ec78684b..4541f9cb72f 100644
--- a/lib/private/DB/OracleMigrator.php
+++ b/lib/private/DB/OracleMigrator.php
@@ -30,6 +30,7 @@ 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 NoCheckMigrator {
 
@@ -81,6 +82,27 @@ class OracleMigrator extends NoCheckMigrator {
 		);
 	}
 
+	/**
+	 * 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
@@ -100,7 +122,9 @@ class OracleMigrator extends NoCheckMigrator {
 				array_map(function(Index $index) {
 					return $this->quoteIndex($index);
 				}, $table->getIndexes()),
-				$table->getForeignKeys(),
+				array_map(function(ForeignKeyConstraint $fck) {
+					return $this->quoteForeignKeyConstraint($fck);
+				}, $table->getForeignKeys()),
 				0,
 				$table->getOptions()
 			);
@@ -158,9 +182,17 @@ class OracleMigrator extends NoCheckMigrator {
 				return $this->quoteIndex($index);
 			}, $tableDiff->renamedIndexes);
 
-			// TODO handle $tableDiff->addedForeignKeys
-			// TODO handle $tableDiff->changedForeignKeys
-			// TODO handle $tableDiff->removedForeignKeys
+			$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;
diff --git a/tests/lib/DB/MigratorTest.php b/tests/lib/DB/MigratorTest.php
index e4f45c4bb86..ea718240c5e 100644
--- a/tests/lib/DB/MigratorTest.php
+++ b/tests/lib/DB/MigratorTest.php
@@ -41,6 +41,9 @@ class MigratorTest extends \Test\TestCase {
 	/** @var string */
 	private $tableName;
 
+	/** @var string */
+	private $tableNameTmp;
+
 	protected function setUp() {
 		parent::setUp();
 
@@ -50,11 +53,23 @@ class MigratorTest extends \Test\TestCase {
 			$this->markTestSkipped('DB migration tests are not supported on OCI');
 		}
 		$this->manager = new \OC\DB\MDB2SchemaManager($this->connection);
-		$this->tableName = strtolower($this->getUniqueID($this->config->getSystemValue('dbtableprefix', 'oc_') . 'test_'));
+		$this->tableName = $this->getUniqueTableName();
+		$this->tableNameTmp = $this->getUniqueTableName();
+	}
+
+	private function getUniqueTableName() {
+		return strtolower($this->getUniqueID($this->config->getSystemValue('dbtableprefix', 'oc_') . 'test_'));
 	}
 
 	protected function tearDown() {
-		$this->connection->exec('DROP TABLE ' . $this->tableName);
+		// Try to delete if exists (IF EXISTS NOT SUPPORTED IN ORACLE)
+		try {
+			$this->connection->exec('DROP TABLE ' . $this->connection->quoteIdentifier($this->tableNameTmp));
+		} catch (\Doctrine\DBAL\DBALException $e) {}
+
+		try {
+			$this->connection->exec('DROP TABLE ' . $this->connection->quoteIdentifier($this->tableName));
+		} catch (\Doctrine\DBAL\DBALException $e) {}
 		parent::tearDown();
 	}
 
@@ -200,4 +215,24 @@ class MigratorTest extends \Test\TestCase {
 
 		$this->assertTrue(true);
 	}
+
+	public function testAddingForeignKey() {
+		$startSchema = new Schema([], [], $this->getSchemaConfig());
+		$table = $startSchema->createTable($this->tableName);
+		$table->addColumn('id', 'integer', ['autoincrement' => true]);
+		$table->addColumn('name', 'string');
+		$table->setPrimaryKey(['id']);
+
+		$fkName = "fkc";
+		$tableFk = $startSchema->createTable($this->tableNameTmp);
+		$tableFk->addColumn('fk_id', 'integer');
+		$tableFk->addColumn('name', 'string');
+		$tableFk->addForeignKeyConstraint($this->tableName, array('fk_id'), array('id'), array(), $fkName);
+
+		$migrator = $this->manager->getMigrator();
+		$migrator->migrate($startSchema);
+
+
+		$this->assertTrue($startSchema->getTable($this->tableNameTmp)->hasForeignKey($fkName));
+	}
 }
-- 
GitLab