From ecfe9f49e9b5cd35a8013332c5dcbec376459655 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Thu, 6 Jun 2019 23:48:58 -0500 Subject: [PATCH] Added disableForeignKeyConstraints and enableForeignKeyConstraints methods to make migrations with FKs easier. Fixes #1964 --- system/Database/BaseConnection.php | 24 ++++++++++++++++++++++ system/Database/Forge.php | 4 ++-- system/Database/MySQLi/Connection.php | 24 ++++++++++++++++++++++ system/Database/Postgre/Connection.php | 24 ++++++++++++++++++++++ system/Database/SQLite3/Connection.php | 24 ++++++++++++++++++++++ user_guide_src/source/dbmgmt/migration.rst | 18 ++++++++++++++++ 6 files changed, 116 insertions(+), 2 deletions(-) diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 496c77f2a2f0..8bcbac95dc28 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -1697,6 +1697,30 @@ public function getForeignKeyData(string $table) //-------------------------------------------------------------------- + /** + * Disables foreign key checks temporarily. + */ + public function disableForeignKeyChecks() + { + $sql = $this->_disableForeignKeyChecks(); + + return $this->query($sql); + } + + //-------------------------------------------------------------------- + + /** + * Enables foreign key checks temporarily. + */ + public function enableForeignKeyChecks() + { + $sql = $this->_enableForeignKeyChecks(); + + return $this->query($sql); + } + + //-------------------------------------------------------------------- + /** * Allows the engine to be set into a mode where queries are not * actually executed, but they are still generated, timed, etc. diff --git a/system/Database/Forge.php b/system/Database/Forge.php index 8806a86cc8e3..6aae0d9079b3 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -615,11 +615,11 @@ public function dropTable(string $tableName, bool $ifExists = false, bool $casca return true; } - $this->db->query('PRAGMA foreign_keys = OFF'); + $this->db->disableForeignKeyChecks(); $query = $this->db->query($query); - $this->db->query('PRAGMA foreign_keys = ON'); + $this->db->enableForeignKeyChecks(); // Update table list cache if ($query && ! empty($this->db->dataCache['table_names'])) diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index 6edc28cfb230..4a455ff267f3 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -568,6 +568,30 @@ public function _foreignKeyData(string $table): array //-------------------------------------------------------------------- + /** + * Returns platform-specific SQL to disable foreign key checks. + * + * @return string + */ + protected function _disableForeignKeyChecks() + { + return 'SET FOREIGN_KEY_CHECKS=0'; + } + + //-------------------------------------------------------------------- + + /** + * Returns platform-specific SQL to enable foreign key checks. + * + * @return string + */ + protected function _enableForeignKeyChecks() + { + return 'SET FOREIGN_KEY_CHECKS=1'; + } + + //-------------------------------------------------------------------- + /** * Returns the last error code and message. * diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index d69314b78218..8becda2aef67 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -418,6 +418,30 @@ public function _foreignKeyData(string $table): array //-------------------------------------------------------------------- + /** + * Returns platform-specific SQL to disable foreign key checks. + * + * @return string + */ + protected function _disableForeignKeyChecks() + { + return 'SET CONSTRAINTS ALL DEFERRED'; + } + + //-------------------------------------------------------------------- + + /** + * Returns platform-specific SQL to enable foreign key checks. + * + * @return string + */ + protected function _enableForeignKeyChecks() + { + return 'SET CONSTRAINTS ALL IMMEDIATE;'; + } + + //-------------------------------------------------------------------- + /** * Returns the last error code and message. * diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index dec92fc2efe8..576ebef9cbef 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -417,6 +417,30 @@ public function _foreignKeyData(string $table): array //-------------------------------------------------------------------- + /** + * Returns platform-specific SQL to disable foreign key checks. + * + * @return string + */ + protected function _disableForeignKeyChecks() + { + return 'PRAGMA foreign_keys = OFF'; + } + + //-------------------------------------------------------------------- + + /** + * Returns platform-specific SQL to enable foreign key checks. + * + * @return string + */ + protected function _enableForeignKeyChecks() + { + return 'PRAGMA foreign_keys = ON'; + } + + //-------------------------------------------------------------------- + /** * Returns the last error code and message. * diff --git a/user_guide_src/source/dbmgmt/migration.rst b/user_guide_src/source/dbmgmt/migration.rst index 41a39a6d2ae7..9d7f9654940c 100644 --- a/user_guide_src/source/dbmgmt/migration.rst +++ b/user_guide_src/source/dbmgmt/migration.rst @@ -94,6 +94,24 @@ The database connection and the database Forge class are both available to you t Alternatively, you can use a command-line call to generate a skeleton migration file. See below for more details. +Foreign Keys +============ + +When your tables include Foreign Keys, migrations can often cause problems as you attempt to drop tables and columns. +To temporarily bypass the foreign key checks while running migrations, use the ``disableForeignKeyConstraints()`` and +``enableForeignKeyConstraints()`` methods on the database connection. + +:: + + public function up() + { + $this->db->disableForeignKeyConstraints(); + + // Migration rules would go here... + + $this->db->enableForeignKeyConstraints(); + } + Using $currentVersion =====================