From 737dd9f6b8965ad14e2fbe50986f03eb575db478 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Sun, 1 Dec 2019 15:00:28 -0500 Subject: [PATCH] Fix foreign keys in MySQL --- CHANGELOG | 6 ++++ UPGRADING | 10 ++++++ lib/Database.php | 6 ++-- sql/MySQL/5.sql | 49 +++++++++++++++++++++++++++++ sql/PostgreSQL/5.sql | 7 +++++ sql/SQLite3/5.sql | 7 +++++ tests/lib/DatabaseDrivers/MySQL.php | 4 +++ 7 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 sql/MySQL/5.sql create mode 100644 sql/PostgreSQL/5.sql create mode 100644 sql/SQLite3/5.sql diff --git a/CHANGELOG b/CHANGELOG index a381c82..ae28fc0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +Version 0.8.2 (????-??-??) +========================== + +Bug fixes: +- Enforce foreign key constraints in MySQL + Version 0.8.1 (2019-10-28) ========================== diff --git a/UPGRADING b/UPGRADING index c96f41c..e0fa200 100644 --- a/UPGRADING +++ b/UPGRADING @@ -10,6 +10,15 @@ usually prudent: - If installing from source, update dependencies with: `composer install -o --no-dev` + +Upgrading from 0.8.1 to 0.8.2 +============================= + +- The database schema has changed from rev5 to rev6; if upgrading the database + manually, apply the 5.sql file. MySQL databases may need manual + intervention to ensure foreign key constraints are not violated + + Upgrading from 0.7.1 to 0.8.0 ============================= @@ -22,6 +31,7 @@ Upgrading from 0.7.1 to 0.8.0 - zendframework/zend-diactoros (version 2.x) - zendframework/zend-httphandlerrunner + Upgrading from 0.5.1 to 0.6.0 ============================= diff --git a/lib/Database.php b/lib/Database.php index 4036f91..bcca3eb 100644 --- a/lib/Database.php +++ b/lib/Database.php @@ -39,7 +39,7 @@ use JKingWeb\Arsse\Misc\URL; */ class Database { /** The version number of the latest schema the interface is aware of */ - const SCHEMA_VERSION = 5; + const SCHEMA_VERSION = 6; /** The size of a set of values beyond which the set will be embedded into the query text */ const LIMIT_SET_SIZE = 25; /** The length of a string in an embedded set beyond which a parameter placeholder will be used for the string */ @@ -50,7 +50,7 @@ class Database { const ASSOC_ADD = 1; /** Makes tag/label association change operations replace members */ const ASSOC_REPLACE = 2; - /** A map database driver short-names and their associated class names */ + /** A map of database driver short-names and their associated class names */ const DRIVER_NAMES = [ 'sqlite3' => \JKingWeb\Arsse\Db\SQLite3\Driver::class, 'postgresql' => \JKingWeb\Arsse\Db\PostgreSQL\Driver::class, @@ -520,7 +520,7 @@ class Database { if (!ValueInfo::id($id)) { throw new Db\ExceptionInput("typeViolation", ["action" => __FUNCTION__, "field" => "folder", 'type' => "int > 0"]); } - $changes = $this->db->prepare("WITH RECURSIVE folders(folder) as (SELECT ? union select id from arsse_folders join folders on parent = folder) DELETE FROM arsse_folders where owner = ? and id in (select folder from folders)", "int", "str")->run($id, $user)->changes(); + $changes = $this->db->prepare("DELETE FROM arsse_folders where owner = ? and id = ?", "str", "int")->run($user, $id)->changes(); if (!$changes) { throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "folder", 'id' => $id]); } diff --git a/sql/MySQL/5.sql b/sql/MySQL/5.sql new file mode 100644 index 0000000..7e8ef7e --- /dev/null +++ b/sql/MySQL/5.sql @@ -0,0 +1,49 @@ +-- SPDX-License-Identifier: MIT +-- Copyright 2017 J. King, Dustin Wilson et al. +-- See LICENSE and AUTHORS files for details + +-- Please consult the SQLite 3 schemata for commented version + +-- Correct character set and collation of sessions table +alter table arsse_sessions default character set utf8mb4 collate utf8mb4_unicode_ci; +alter table arsse_sessions convert to character set utf8mb4 collate utf8mb4_unicode_ci; + +-- Make integer foreign key referrers unsigned to match serial-type keys +alter table arsse_folders modify parent bigint unsigned; +alter table arsse_subscriptions modify feed bigint unsigned not null; +alter table arsse_subscriptions modify folder bigint unsigned; +alter table arsse_articles modify feed bigint unsigned not null; +alter table arsse_enclosures modify article bigint unsigned not null; +alter table arsse_marks modify article bigint unsigned not null; +alter table arsse_marks modify subscription bigint unsigned not null; +alter table arsse_editions modify article bigint unsigned not null; +alter table arsse_categories modify article bigint unsigned not null; +alter table arsse_label_members modify label bigint unsigned not null; +alter table arsse_label_members modify article bigint unsigned not null; +alter table arsse_label_members modify subscription bigint unsigned not null; +alter table arsse_tag_members modify tag bigint unsigned not null; +alter table arsse_tag_members modify subscription bigint unsigned not null; + +-- Fix foreign key constraints +alter table arsse_folders add foreign key(owner) references arsse_users(id) on delete cascade on update cascade; +alter table arsse_folders add foreign key(parent) references arsse_folders(id) on delete cascade; +alter table arsse_subscriptions add foreign key(owner) references arsse_users(id) on delete cascade on update cascade; +alter table arsse_subscriptions add foreign key(feed) references arsse_feeds(id) on delete cascade; +alter table arsse_subscriptions add foreign key(folder) references arsse_folders(id) on delete cascade; +alter table arsse_articles add foreign key(feed) references arsse_feeds(id) on delete cascade; +alter table arsse_enclosures add foreign key(article) references arsse_articles(id) on delete cascade; +alter table arsse_marks add foreign key(article) references arsse_articles(id) on delete cascade; +alter table arsse_marks add foreign key(subscription) references arsse_subscriptions(id) on delete cascade; +alter table arsse_editions add foreign key(article) references arsse_articles(id) on delete cascade; +alter table arsse_categories add foreign key(article) references arsse_articles(id) on delete cascade; +alter table arsse_sessions add foreign key("user") references arsse_users(id) on delete cascade on update cascade; +alter table arsse_labels add foreign key(owner) references arsse_users(id) on delete cascade on update cascade; +alter table arsse_label_members add foreign key(label) references arsse_labels(id) on delete cascade; +alter table arsse_label_members add foreign key(article) references arsse_articles(id) on delete cascade; +alter table arsse_label_members add foreign key(subscription) references arsse_subscriptions(id) on delete cascade; +alter table arsse_tags add foreign key(owner) references arsse_users(id) on delete cascade on update cascade; +alter table arsse_tag_members add foreign key(tag) references arsse_tags(id) on delete cascade; +alter table arsse_tag_members add foreign key(subscription) references arsse_subscriptions(id) on delete cascade; +alter table arsse_tokens add foreign key("user") references arsse_users(id) on delete cascade on update cascade; + +update arsse_meta set value = '6' where "key" = 'schema_version'; diff --git a/sql/PostgreSQL/5.sql b/sql/PostgreSQL/5.sql new file mode 100644 index 0000000..ac48a43 --- /dev/null +++ b/sql/PostgreSQL/5.sql @@ -0,0 +1,7 @@ +-- SPDX-License-Identifier: MIT +-- Copyright 2017 J. King, Dustin Wilson et al. +-- See LICENSE and AUTHORS files for details + +-- Please consult the SQLite 3 schemata for commented version + +update arsse_meta set value = '6' where "key" = 'schema_version'; diff --git a/sql/SQLite3/5.sql b/sql/SQLite3/5.sql new file mode 100644 index 0000000..24c5b91 --- /dev/null +++ b/sql/SQLite3/5.sql @@ -0,0 +1,7 @@ +-- SPDX-License-Identifier: MIT +-- Copyright 2017 J. King, Dustin Wilson et al. +-- See LICENSE and AUTHORS files for details + +-- set version marker +pragma user_version = 6; +update arsse_meta set value = '6' where "key" = 'schema_version'; diff --git a/tests/lib/DatabaseDrivers/MySQL.php b/tests/lib/DatabaseDrivers/MySQL.php index 048266d..332f3d9 100644 --- a/tests/lib/DatabaseDrivers/MySQL.php +++ b/tests/lib/DatabaseDrivers/MySQL.php @@ -48,6 +48,7 @@ trait MySQL { $db->query("UNLOCK TABLES; ROLLBACK"); } catch (\Throwable $e) { } + $db->query("SET FOREIGN_KEY_CHECKS=0"); foreach (self::dbTableList($db) as $table) { if ($table === "arsse_meta") { $db->query("DELETE FROM $table where `key` <> 'schema_version'"); @@ -56,6 +57,7 @@ trait MySQL { } $db->query("ALTER TABLE $table auto_increment = 1"); } + $db->query("SET FOREIGN_KEY_CHECKS=1"); foreach ($afterStatements as $st) { $db->query($st); } @@ -67,9 +69,11 @@ trait MySQL { $db->query("UNLOCK TABLES; ROLLBACK"); } catch (\Throwable $e) { } + $db->query("SET FOREIGN_KEY_CHECKS=0"); foreach (self::dbTableList($db) as $table) { $db->query("DROP TABLE IF EXISTS $table"); } + $db->query("SET FOREIGN_KEY_CHECKS=1"); foreach ($afterStatements as $st) { $db->query($st); }