From 5d45d6da2cc47e390e753de5a34bec1016f454ae Mon Sep 17 00:00:00 2001 From: Marcin Kurczewski Date: Sat, 14 Dec 2013 11:14:36 +0100 Subject: [PATCH] Support for MySQL --- data/config.ini | 5 +- src/Controllers/IndexController.php | 2 +- src/Models/Model_Property.php | 2 +- src/Upgrades/mysql/Upgrade1.sql | 84 ++++++++++++++++++++++++++ src/Upgrades/{ => mysql}/Upgrade2.sql | 0 src/Upgrades/mysql/Upgrade3.sql | 10 +++ src/Upgrades/mysql/Upgrade4.sql | 30 +++++++++ src/Upgrades/mysql/Upgrade5.sql | 1 + src/Upgrades/mysql/Upgrade6.sql | 11 ++++ src/Upgrades/{ => mysql}/Upgrade7.sql | 0 src/Upgrades/{ => mysql}/Upgrade8.sql | 2 +- src/Upgrades/{ => sqlite}/Upgrade1.sql | 54 ++++++++--------- src/Upgrades/sqlite/Upgrade2.sql | 1 + src/Upgrades/{ => sqlite}/Upgrade3.sql | 0 src/Upgrades/{ => sqlite}/Upgrade4.sql | 0 src/Upgrades/{ => sqlite}/Upgrade5.sql | 0 src/Upgrades/{ => sqlite}/Upgrade6.sql | 0 src/Upgrades/sqlite/Upgrade7.sql | 3 + src/Upgrades/sqlite/Upgrade8.sql | 37 ++++++++++++ src/core.php | 14 ++--- upgrade.php | 62 +++++++++++++++---- 21 files changed, 269 insertions(+), 49 deletions(-) create mode 100644 src/Upgrades/mysql/Upgrade1.sql rename src/Upgrades/{ => mysql}/Upgrade2.sql (100%) create mode 100644 src/Upgrades/mysql/Upgrade3.sql create mode 100644 src/Upgrades/mysql/Upgrade4.sql create mode 100644 src/Upgrades/mysql/Upgrade5.sql create mode 100644 src/Upgrades/mysql/Upgrade6.sql rename src/Upgrades/{ => mysql}/Upgrade7.sql (100%) rename src/Upgrades/{ => mysql}/Upgrade8.sql (95%) rename src/Upgrades/{ => sqlite}/Upgrade1.sql (100%) create mode 100644 src/Upgrades/sqlite/Upgrade2.sql rename src/Upgrades/{ => sqlite}/Upgrade3.sql (100%) rename src/Upgrades/{ => sqlite}/Upgrade4.sql (100%) rename src/Upgrades/{ => sqlite}/Upgrade5.sql (100%) rename src/Upgrades/{ => sqlite}/Upgrade6.sql (100%) create mode 100644 src/Upgrades/sqlite/Upgrade7.sql create mode 100644 src/Upgrades/sqlite/Upgrade8.sql diff --git a/data/config.ini b/data/config.ini index 68c3c000..cd9da656 100644 --- a/data/config.ini +++ b/data/config.ini @@ -2,7 +2,10 @@ prettyPrint=1 [main] -dbPath = "./data/db.sqlite" +dbDriver = "sqlite" +dbLocation = "./data/db.sqlite" +dbUser = "test" +dbPass = "test" filesPath = "./data/files/" thumbsPath = "./data/thumbs/" logsPath = "./data/logs/" diff --git a/src/Controllers/IndexController.php b/src/Controllers/IndexController.php index dba5b861..39ead30b 100644 --- a/src/Controllers/IndexController.php +++ b/src/Controllers/IndexController.php @@ -64,7 +64,7 @@ class IndexController ->from('post') ->where('type = ?')->put(PostType::Image) ->and('safety = ?')->put(PostSafety::Safe) - ->orderBy('random()') + ->orderBy($this->config->main->dbDriver == 'sqlite' ? 'random()' : 'rand()') ->desc() ->get('row')['id']; if (!$featuredPostId) diff --git a/src/Models/Model_Property.php b/src/Models/Model_Property.php index c59f44d5..63b23dc9 100644 --- a/src/Models/Model_Property.php +++ b/src/Models/Model_Property.php @@ -4,7 +4,7 @@ class Model_Property extends RedBean_SimpleModel const FeaturedPostId = 0; const FeaturedPostUserName = 1; const FeaturedPostDate = 2; - const DbVersion = 'db-version'; + const DbVersion = 3; static $allProperties = null; diff --git a/src/Upgrades/mysql/Upgrade1.sql b/src/Upgrades/mysql/Upgrade1.sql new file mode 100644 index 00000000..92c0146e --- /dev/null +++ b/src/Upgrades/mysql/Upgrade1.sql @@ -0,0 +1,84 @@ +CREATE TABLE property +( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + prop_id INTEGER, + value TEXT +); + +CREATE TABLE user +( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + name TEXT, + pass_salt TEXT, + pass_hash TEXT, + staff_confirmed INTEGER, + email_unconfirmed TEXT, + email_confirmed TEXT, + email_token TEXT, + join_date INTEGER, + access_rank INTEGER, + settings TEXT +); + +CREATE TABLE post +( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + type INTEGER, + name TEXT, + orig_name TEXT, + file_hash TEXT, + file_size INTEGER, + mime_type TEXT, + safety INTEGER, + hidden INTEGER, + upload_date INTEGER, + image_width INTEGER, + image_height INTEGER, + uploader_id INTEGER, + source TEXT, + FOREIGN KEY(uploader_id) REFERENCES user(id) ON DELETE SET NULL ON UPDATE SET NULL +); +CREATE INDEX idx_fk_post_uploader_id ON post(uploader_id); + +CREATE TABLE tag +( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + name TEXT +); + +CREATE TABLE post_tag +( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + tag_id INTEGER, + post_id INTEGER, + FOREIGN KEY(tag_id) REFERENCES tag(id) ON DELETE CASCADE ON UPDATE SET NULL, + FOREIGN KEY(post_id) REFERENCES post(id) ON DELETE CASCADE ON UPDATE SET NULL +); +CREATE INDEX idx_fk_post_tag_post_id ON post_tag(post_id); +CREATE INDEX idx_fk_post_tag_tag_id ON post_tag(tag_id); +CREATE UNIQUE INDEX idx_uq_post_tag_tag_id_post_id ON post_tag(tag_id, post_id); + +CREATE TABLE favoritee +( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + post_id INTEGER, + user_id INTEGER, + FOREIGN KEY(user_id) REFERENCES user(id) ON DELETE CASCADE ON UPDATE SET NULL, + FOREIGN KEY(post_id) REFERENCES post(id) ON DELETE CASCADE ON UPDATE SET NULL +); +CREATE INDEX idx_fk_favoritee_post_id ON favoritee(post_id); +CREATE INDEX idx_fk_favoritee_user_id ON favoritee(user_id); +CREATE UNIQUE INDEX idx_uq_favoritee_post_id_user_id ON favoritee(post_id, user_id); + +CREATE TABLE comment +( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + post_id INTEGER, + commenter_id INTEGER, + comment_date INTEGER, + text TEXT, + FOREIGN KEY(post_id) REFERENCES post(id) ON DELETE CASCADE ON UPDATE SET NULL, + FOREIGN KEY(commenter_id) REFERENCES user(id) ON DELETE SET NULL ON UPDATE SET NULL +); +CREATE INDEX idx_fk_comment_commenter_id ON comment(commenter_id); +CREATE INDEX idx_fk_comment_post_id ON comment(post_id); diff --git a/src/Upgrades/Upgrade2.sql b/src/Upgrades/mysql/Upgrade2.sql similarity index 100% rename from src/Upgrades/Upgrade2.sql rename to src/Upgrades/mysql/Upgrade2.sql diff --git a/src/Upgrades/mysql/Upgrade3.sql b/src/Upgrades/mysql/Upgrade3.sql new file mode 100644 index 00000000..aef93ff2 --- /dev/null +++ b/src/Upgrades/mysql/Upgrade3.sql @@ -0,0 +1,10 @@ +CREATE TABLE crossref +( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + post_id INTEGER, + post2_id INTEGER, + FOREIGN KEY(post_id) REFERENCES post(id) ON DELETE CASCADE ON UPDATE SET NULL, + FOREIGN KEY(post2_id) REFERENCES post(id) ON DELETE CASCADE ON UPDATE SET NULL +); +CREATE INDEX idx_fk_crossref_post_id ON crossref(post_id); +CREATE INDEX idx_fk_crossref_post2_id ON crossref(post2_id); diff --git a/src/Upgrades/mysql/Upgrade4.sql b/src/Upgrades/mysql/Upgrade4.sql new file mode 100644 index 00000000..7f7e9b9b --- /dev/null +++ b/src/Upgrades/mysql/Upgrade4.sql @@ -0,0 +1,30 @@ +ALTER TABLE post ADD COLUMN score INTEGER NOT NULL DEFAULT 0; + +UPDATE post SET score = 0; + +CREATE TABLE post_score +( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + post_id INTEGER, + user_id INTEGER, + score INTEGER, + FOREIGN KEY(post_id) REFERENCES post(id) ON DELETE CASCADE ON UPDATE SET NULL, + FOREIGN KEY(user_id) REFERENCES user(id) ON DELETE CASCADE ON UPDATE SET NULL +); +CREATE INDEX idx_fk_post_score_post_id ON post_score(post_id); +CREATE INDEX idx_fk_post_score_user_id ON post_score(user_id); + +CREATE TRIGGER post_score_update AFTER UPDATE ON post_score FOR EACH ROW +BEGIN + UPDATE post SET score = post.score - old.score + new.score WHERE post.id = new.post_id; +END; + +CREATE TRIGGER post_score_insert AFTER INSERT ON post_score FOR EACH ROW +BEGIN + UPDATE post SET score = post.score + new.score WHERE post.id = new.post_id; +END; + +CREATE TRIGGER post_score_delete BEFORE DELETE ON post_score FOR EACH ROW +BEGIN + UPDATE post SET score = post.score - old.score WHERE post.id = old.post_id; +END; diff --git a/src/Upgrades/mysql/Upgrade5.sql b/src/Upgrades/mysql/Upgrade5.sql new file mode 100644 index 00000000..5b514c95 --- /dev/null +++ b/src/Upgrades/mysql/Upgrade5.sql @@ -0,0 +1 @@ +ALTER TABLE post_score RENAME TO postscore; diff --git a/src/Upgrades/mysql/Upgrade6.sql b/src/Upgrades/mysql/Upgrade6.sql new file mode 100644 index 00000000..4dff95de --- /dev/null +++ b/src/Upgrades/mysql/Upgrade6.sql @@ -0,0 +1,11 @@ +ALTER TABLE user DROP COLUMN email_token; + +CREATE TABLE usertoken +( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + user_id INTEGER, + token VARCHAR(32), + used BOOLEAN, + expires INTEGER --TIMESTAMP +); +CREATE INDEX idx_fk_usertoken_user_id ON usertoken(user_id); diff --git a/src/Upgrades/Upgrade7.sql b/src/Upgrades/mysql/Upgrade7.sql similarity index 100% rename from src/Upgrades/Upgrade7.sql rename to src/Upgrades/mysql/Upgrade7.sql diff --git a/src/Upgrades/Upgrade8.sql b/src/Upgrades/mysql/Upgrade8.sql similarity index 95% rename from src/Upgrades/Upgrade8.sql rename to src/Upgrades/mysql/Upgrade8.sql index f128585b..bbe49246 100644 --- a/src/Upgrades/Upgrade8.sql +++ b/src/Upgrades/mysql/Upgrade8.sql @@ -2,7 +2,7 @@ ALTER TABLE post ADD COLUMN tag_count INTEGER NOT NULL DEFAULT 0; ALTER TABLE post ADD COLUMN fav_count INTEGER NOT NULL DEFAULT 0; ALTER TABLE post ADD COLUMN comment_count INTEGER NOT NULL DEFAULT 0; -UPDATE POST SET tag_count = (SELECT COUNT(*) FROM post_tag WHERE post_id = post.id); +UPDATE post SET tag_count = (SELECT COUNT(*) FROM post_tag WHERE post_id = post.id); UPDATE post SET fav_count = (SELECT COUNT(*) FROM favoritee WHERE post_id = post.id); UPDATE post SET comment_count = (SELECT COUNT(*) FROM comment WHERE post_id = post.id); diff --git a/src/Upgrades/Upgrade1.sql b/src/Upgrades/sqlite/Upgrade1.sql similarity index 100% rename from src/Upgrades/Upgrade1.sql rename to src/Upgrades/sqlite/Upgrade1.sql index 8d167f6a..b0bc005d 100644 --- a/src/Upgrades/Upgrade1.sql +++ b/src/Upgrades/sqlite/Upgrade1.sql @@ -1,3 +1,10 @@ +CREATE TABLE property +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + prop_id INTEGER, + value TEXT +); + CREATE TABLE user ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -13,6 +20,26 @@ CREATE TABLE user settings TEXT ); +CREATE TABLE post +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + type INTEGER, + name TEXT, + orig_name TEXT, + file_hash TEXT, + file_size INTEGER, + mime_type TEXT, + safety INTEGER, + hidden INTEGER, + upload_date INTEGER, + image_width INTEGER, + image_height INTEGER, + uploader_id INTEGER, + source TEXT, + FOREIGN KEY(uploader_id) REFERENCES user(id) ON DELETE SET NULL ON UPDATE SET NULL +); +CREATE INDEX idx_fk_post_uploader_id ON post(uploader_id); + CREATE TABLE tag ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -55,30 +82,3 @@ CREATE TABLE comment ); CREATE INDEX idx_fk_comment_commenter_id ON comment(commenter_id); CREATE INDEX idx_fk_comment_post_id ON comment(post_id); - -CREATE TABLE post -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - type INTEGER, - name TEXT, - orig_name TEXT, - file_hash TEXT, - file_size INTEGER, - mime_type TEXT, - safety INTEGER, - hidden INTEGER, - upload_date INTEGER, - image_width INTEGER, - image_height INTEGER, - uploader_id INTEGER, - source TEXT, - FOREIGN KEY(uploader_id) REFERENCES user(id) ON DELETE SET NULL ON UPDATE SET NULL -); -CREATE INDEX idx_fk_post_uploader_id ON post(uploader_id); - -CREATE TABLE property -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - prop_id INTEGER, - value TEXT -); diff --git a/src/Upgrades/sqlite/Upgrade2.sql b/src/Upgrades/sqlite/Upgrade2.sql new file mode 100644 index 00000000..77a34683 --- /dev/null +++ b/src/Upgrades/sqlite/Upgrade2.sql @@ -0,0 +1 @@ +ALTER TABLE user ADD COLUMN banned INTEGER; diff --git a/src/Upgrades/Upgrade3.sql b/src/Upgrades/sqlite/Upgrade3.sql similarity index 100% rename from src/Upgrades/Upgrade3.sql rename to src/Upgrades/sqlite/Upgrade3.sql diff --git a/src/Upgrades/Upgrade4.sql b/src/Upgrades/sqlite/Upgrade4.sql similarity index 100% rename from src/Upgrades/Upgrade4.sql rename to src/Upgrades/sqlite/Upgrade4.sql diff --git a/src/Upgrades/Upgrade5.sql b/src/Upgrades/sqlite/Upgrade5.sql similarity index 100% rename from src/Upgrades/Upgrade5.sql rename to src/Upgrades/sqlite/Upgrade5.sql diff --git a/src/Upgrades/Upgrade6.sql b/src/Upgrades/sqlite/Upgrade6.sql similarity index 100% rename from src/Upgrades/Upgrade6.sql rename to src/Upgrades/sqlite/Upgrade6.sql diff --git a/src/Upgrades/sqlite/Upgrade7.sql b/src/Upgrades/sqlite/Upgrade7.sql new file mode 100644 index 00000000..ec16fbcf --- /dev/null +++ b/src/Upgrades/sqlite/Upgrade7.sql @@ -0,0 +1,3 @@ +CREATE UNIQUE INDEX idx_uq_postscore_post_id_user_id ON postscore(post_id, user_id); +CREATE UNIQUE INDEX idx_uq_crossref_post_id_post2_id ON crossref(post_id, post2_id); + diff --git a/src/Upgrades/sqlite/Upgrade8.sql b/src/Upgrades/sqlite/Upgrade8.sql new file mode 100644 index 00000000..bbe49246 --- /dev/null +++ b/src/Upgrades/sqlite/Upgrade8.sql @@ -0,0 +1,37 @@ +ALTER TABLE post ADD COLUMN tag_count INTEGER NOT NULL DEFAULT 0; +ALTER TABLE post ADD COLUMN fav_count INTEGER NOT NULL DEFAULT 0; +ALTER TABLE post ADD COLUMN comment_count INTEGER NOT NULL DEFAULT 0; + +UPDATE post SET tag_count = (SELECT COUNT(*) FROM post_tag WHERE post_id = post.id); +UPDATE post SET fav_count = (SELECT COUNT(*) FROM favoritee WHERE post_id = post.id); +UPDATE post SET comment_count = (SELECT COUNT(*) FROM comment WHERE post_id = post.id); + +CREATE TRIGGER post_tag_insert AFTER INSERT ON post_tag FOR EACH ROW +BEGIN + UPDATE post SET tag_count = tag_count + 1 WHERE post.id = new.post_id; +END; + +CREATE TRIGGER post_tag_delete BEFORE DELETE ON post_tag FOR EACH ROW +BEGIN + UPDATE post SET tag_count = tag_count - 1 WHERE post.id = old.post_id; +END; + +CREATE TRIGGER favoritee_insert AFTER INSERT ON favoritee FOR EACH ROW +BEGIN + UPDATE post SET fav_count = fav_count + 1 WHERE post.id = new.post_id; +END; + +CREATE TRIGGER favoritee_delete BEFORE DELETE ON favoritee FOR EACH ROW +BEGIN + UPDATE post SET fav_count = fav_count - 1 WHERE post.id = old.post_id; +END; + +CREATE TRIGGER comment_insert AFTER INSERT ON comment FOR EACH ROW +BEGIN + UPDATE post SET comment_count = comment_count + 1 WHERE post.id = new.post_id; +END; + +CREATE TRIGGER comment_delete BEFORE DELETE ON comment FOR EACH ROW +BEGIN + UPDATE post SET comment_count = comment_count - 1 WHERE post.id = old.post_id; +END; diff --git a/src/core.php b/src/core.php index 563db5f0..1d2d320d 100644 --- a/src/core.php +++ b/src/core.php @@ -10,12 +10,6 @@ date_default_timezone_set('UTC'); setlocale(LC_CTYPE, 'en_US.UTF-8'); ini_set('memory_limit', '128M'); -//extension sanity checks -$requiredExtensions = ['pdo', 'pdo_sqlite', 'gd', 'openssl', 'fileinfo']; -foreach ($requiredExtensions as $ext) - if (!extension_loaded($ext)) - die('PHP extension "' . $ext . '" must be enabled to continue.' . PHP_EOL); - //basic include calls, autoloader init require_once $rootDir . 'lib' . DS . 'php-markdown' . DS . 'Michelf' . DS . 'Markdown.php'; require_once $rootDir . 'lib' . DS . 'redbean' . DS . 'RedBean' . DS . 'redbean.inc.php'; @@ -34,6 +28,12 @@ foreach ($configPaths as $path) $config->loadIni($path); \Chibi\Registry::setConfig($config); +//extension sanity checks +$requiredExtensions = ['pdo', 'pdo_' . $config->main->dbDriver, 'gd', 'openssl', 'fileinfo']; +foreach ($requiredExtensions as $ext) + if (!extension_loaded($ext)) + die('PHP extension "' . $ext . '" must be enabled to continue.' . PHP_EOL); + //prepare context \Chibi\Facade::init(); $context = \Chibi\Registry::getContext(); @@ -41,7 +41,7 @@ $context->startTime = $startTime; $context->rootDir = $rootDir; //load database -R::setup('sqlite:' . TextHelper::absolutePath($config->main->dbPath)); +R::setup($config->main->dbDriver . ':' . TextHelper::absolutePath($config->main->dbLocation), $config->main->dbUser, $config->main->dbPass); R::freeze(true); R::dependencies(['tag' => ['post'], 'favoritee' => ['post', 'user'], 'comment' => ['post', 'user']]); diff --git a/upgrade.php b/upgrade.php index 5a1e855d..896a4ea0 100644 --- a/upgrade.php +++ b/upgrade.php @@ -2,32 +2,72 @@ require_once 'src/core.php'; $config = \Chibi\Registry::getConfig(); -$dbVersion = Model_Property::get(Model_Property::DbVersion); -printf('DB version = %d' . PHP_EOL, $dbVersion); +function getDbVersion() +{ + $dbVersion = Model_Property::get(Model_Property::DbVersion); + if (strpos($dbVersion, '.') !== false) + { + list ($dbVersionMajor, $dbVersionMinor) = explode('.', $dbVersion); + } + elseif ($dbVersion) + { + $dbVersionMajor = $dbVersion; + $dbVersionMinor = null; + } + else + { + $dbVersionMajor = 0; + $dbVersionMinor = 0; + } + return [$dbVersionMajor, $dbVersionMinor]; +} -$upgradesPath = TextHelper::absolutePath(\Chibi\Registry::getContext()->rootDir . DS . 'src' . DS . 'Upgrades'); +$upgradesPath = TextHelper::absolutePath(\Chibi\Registry::getContext()->rootDir . DS . 'src' . DS . 'Upgrades' . DS . $config->main->dbDriver); $upgrades = glob($upgradesPath . DS . '*.sql'); natcasesort($upgrades); foreach ($upgrades as $upgradePath) { preg_match('/(\d+)\.sql/', $upgradePath, $matches); - $upgradeVersion = intval($matches[1]); + $upgradeVersionMajor = intval($matches[1]); - if ($upgradeVersion > $dbVersion) + list ($dbVersionMajor, $dbVersionMinor) = getDbVersion(); + + if (($upgradeVersionMajor > $dbVersionMajor) or ($upgradeVersionMajor == $dbVersionMajor and $dbVersionMinor !== null)) { - printf('Executing %s...' . PHP_EOL, $upgradePath); + printf('%s: executing' . PHP_EOL, $upgradePath); $upgradeSql = file_get_contents($upgradePath); $upgradeSql = preg_replace('/^[ \t]+(.*);/m', '\0--', $upgradeSql); $queries = preg_split('/;\s*[\r\n]+/s', $upgradeSql); $queries = array_map('trim', $queries); + $queries = array_filter($queries); + $upgradeVersionMinor = 0; foreach ($queries as $query) { - echo $query . PHP_EOL; - R::exec($query); - echo PHP_EOL; + $query = preg_replace('/\s*--(.*?)$/m', '', $query); + ++ $upgradeVersionMinor; + if ($upgradeVersionMinor > $dbVersionMinor) + { + try + { + R::exec($query); + } + catch (Exception $e) + { + echo $e . PHP_EOL; + echo $query . PHP_EOL; + die; + } + Model_Property::set(Model_Property::DbVersion, $upgradeVersionMajor . '.' . $upgradeVersionMinor); + } } + Model_Property::set(Model_Property::DbVersion, $upgradeVersionMajor); + } + else + { + printf('%s: no need to execute' . PHP_EOL, $upgradePath); } - - Model_Property::set(Model_Property::DbVersion, $upgradeVersion); } + +list ($dbVersionMajor, $dbVersionMinor) = getDbVersion(); +printf('Database version: %d.%d' . PHP_EOL, $dbVersionMajor, $dbVersionMinor);