From c2d4bf5ccb71aa4d802f07a9bd37d24234cc2660 Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 14 Apr 2024 21:16:36 -0300 Subject: [PATCH] Changed database structure from default UTC_TIMESTAMP() which are not supposed to be supported to triggers update transaction database method --- database/migrations/m0.sql | 76 ++++++++++++++++++++++++---- database/mysql/mysql.cpp | 101 +++++++++++++++++++++++-------------- database/mysql/mysql.h | 2 +- 3 files changed, 130 insertions(+), 49 deletions(-) diff --git a/database/migrations/m0.sql b/database/migrations/m0.sql index 0695568..0e6b2a5 100644 --- a/database/migrations/m0.sql +++ b/database/migrations/m0.sql @@ -18,7 +18,7 @@ CREATE TABLE IF NOT EXISTS accounts ( `nick` VARCHAR(256), `type` INTEGER UNSIGNED NOT NULL, `password` VARCHAR(128), - `created` TIMESTAMP DEFAULT UTC_TIMESTAMP() + `created` TIMESTAMP ); --creating role bindings table @@ -31,12 +31,12 @@ CREATE TABLE IF NOT EXISTS roleBindings ( FOREIGN KEY (role) REFERENCES roles(id) ); ---creating sessings table +--creating sessions table CREATE TABLE IF NOT EXISTS sessions ( `id` INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY, `owner` INTEGER UNSIGNED NOT NULL, - `started` TIMESTAMP DEFAULT UTC_TIMESTAMP(), - `latest` TIMESTAMP DEFAULT UTC_TIMESTAMP(), + `started` TIMESTAMP, + `latest` TIMESTAMP, `access` CHAR(32) NOT NULL UNIQUE, `renew` CHAR(32), `persist` BOOLEAN NOT NULL, @@ -51,7 +51,7 @@ CREATE TABLE IF NOT EXISTS currencies ( `code` VARCHAR(16) NOT NULL UNIQUE, `title` VARCHAR(256), `manual` BOOLEAN NOT NULL, - `added` TIMESTAMP DEFAULT UTC_TIMESTAMP(), + `created` TIMESTAMP, `type` INTEGER UNSIGNED NOT NULL, `value` DECIMAL (20, 5) NOT NULL, `source` TEXT, @@ -61,7 +61,7 @@ CREATE TABLE IF NOT EXISTS currencies ( INDEX manual_idx (manual) ); ---creating assests table +--creating assets table CREATE TABLE IF NOT EXISTS assets ( `id` INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY, `owner` INTEGER UNSIGNED NOT NULL, @@ -72,7 +72,7 @@ CREATE TABLE IF NOT EXISTS assets ( `balance` DECIMAL (20, 5) DEFAULT 0, `type` INTEGER UNSIGNED NOT NULL, `archived` BOOLEAN DEFAULT FALSE, - `created` TIMESTAMP DEFAULT UTC_TIMESTAMP(), + `created` TIMESTAMP, INDEX owner_idx (owner), INDEX archived_idx (archived), @@ -96,8 +96,8 @@ CREATE TABLE IF NOT EXISTS transactions ( `parent` INTEGER UNSIGNED, `value` DECIMAL (20, 5) NOT NULL, `state` INTEGER UNSIGNED DEFAULT 0, - `modified` TIMESTAMP DEFAULT UTC_TIMESTAMP(), - `performed` TIMESTAMP DEFAULT UTC_TIMESTAMP(), + `modified` TIMESTAMP, + `performed` TIMESTAMP, `party` INTEGER UNSIGNED, `notes` TEXT, @@ -114,7 +114,63 @@ CREATE TABLE IF NOT EXISTS transactions ( FOREIGN KEY (party) REFERENCES parties(id) ); ---creating defailt roles +--creating trigger before insert accounts +CREATE TRIGGER before_insert_accounts +BEFORE INSERT ON accounts +FOR EACH ROW +BEGIN + SET NEW.created = UTC_TIMESTAMP(); +END; + +--creating trigger before insert sessions +CREATE TRIGGER before_insert_sessions +BEFORE INSERT ON sessions +FOR EACH ROW +BEGIN + SET NEW.started = UTC_TIMESTAMP(); + SET NEW.latest = UTC_TIMESTAMP(); +END; + +--creating trigger before insert currencies +CREATE TRIGGER before_insert_currencies +BEFORE INSERT ON currencies +FOR EACH ROW +BEGIN + IF NEW.created IS NULL THEN + SET NEW.created = UTC_TIMESTAMP(); + END IF; +END; + +--creating trigger before insert assets +CREATE TRIGGER before_insert_assets +BEFORE INSERT ON assets +FOR EACH ROW +BEGIN + IF NEW.created IS NULL THEN + SET NEW.created = UTC_TIMESTAMP(); + END IF; +END; + +--creating trigger before insert transactions +CREATE TRIGGER before_insert_transactions +BEFORE INSERT ON transactions +FOR EACH ROW +BEGIN + SET NEW.modified = UTC_TIMESTAMP(); + IF NEW.performed IS NULL THEN + SET NEW.performed = UTC_TIMESTAMP(); + END IF; +END; + +--creating trigger before update transactions +CREATE TRIGGER before_update_transactions +BEFORE UPDATE ON transactions +FOR EACH ROW +BEGIN + SET NEW.modified = UTC_TIMESTAMP(); +END; + +--creating default roles INSERT IGNORE INTO roles (`name`) VALUES ('root'), diff --git a/database/mysql/mysql.cpp b/database/mysql/mysql.cpp index 296d37b..d6fb7e3 100644 --- a/database/mysql/mysql.cpp +++ b/database/mysql/mysql.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "mysqld_error.h" @@ -34,6 +35,10 @@ constexpr const char* selectUsedCurrencies = "SELECT DISTINCT c.id, c.code, c.ti constexpr const char* addTransactionQuery = "INSERT INTO transactions" " (`initiator`, `type`, `asset`, `parent`, `value`, `performed`)" " VALUES (?, 1, ?, ?, ?, ?)"; +constexpr const char* updateTransactionQuery = "UPDATE transactions SET" + " `initiator` = ?, `type` = 1, `asset` = ?," + " `parent` = ?, `value` = ?, `performed` = ?" + " WHERE `id` = ?"; static const std::filesystem::path buildSQLPath = "database"; @@ -131,17 +136,15 @@ void DB::MySQL::executeFile (const std::filesystem::path& relativePath) { std::cout << "Executing file " << path << std::endl; std::ifstream inputFile(path); - std::string query; - while (std::getline(inputFile, query, ';')) { - std::optional comment = getComment(query); - while (comment) { - std::cout << '\t' << comment.value() << std::endl; - comment = getComment(query); - } - if (query.empty()) + std::string block, comment; + while (getBlock(inputFile, block, comment)) { + if (!comment.empty()) + std::cout << '\t' << comment << std::endl; + + if (block.empty()) continue; - int result = mysql_query(con, query.c_str()); + int result = mysql_query(con, block.c_str()); if (result != 0) { int errcode = mysql_errno(con); if (errcode == ER_EMPTY_QUERY) @@ -153,6 +156,39 @@ void DB::MySQL::executeFile (const std::filesystem::path& relativePath) { } } +bool DB::MySQL::getBlock(std::ifstream& file, std::string& block, std::string& name) { + if (file.eof()) + return false; + + block.clear(); + name.clear(); + + if (file.peek() == '-') { + file.get(); + if (file.peek() == '-') { + file.get(); + std::getline(file, name); + } else { + file.unget(); + } + } + std::string line; + while (!file.eof()) { + if (file.peek() == '-') + return true; + + if (!std::getline(file, line)) + break; + + if (!block.empty()) + block.append(1, '\n'); + + block += line; + } + + return !block.empty() || !name.empty(); +} + uint8_t DB::MySQL::getVersion () { MYSQL* con = &connection; int result = mysql_query(con, versionQuery); @@ -205,34 +241,6 @@ void DB::MySQL::migrate (uint8_t targetVersion) { std::cout << "Database is now on actual version " << std::to_string(targetVersion) << std::endl; } -std::optional DB::MySQL::getComment (std::string& string) { - ltrim(string); - if (string.length() < 2) - return std::nullopt; - - if (string[0] == '-') { - if (string[1] == '-') { - string.erase(0, 2); - std::string::size_type eol = string.find('\n'); - return extract(string, 0, eol); - } - } else if (string[0] == '/') { - if (string[1] == '*') { - string.erase(0, 2); - std::string::size_type end = 0; - do { - end = string.find(end, '*'); - } while (end != std::string::npos && end < string.size() - 1 && string[end + 1] == '/'); - if (end < string.size() - 1) - end = std::string::npos; - - return extract(string, 0, end); - } - } - - return std::nullopt; -} - uint32_t DB::MySQL::registerAccount (const std::string& login, const std::string& hash) { //TODO validate filed lengths! MYSQL* con = &connection; @@ -429,12 +437,29 @@ DB::Transaction DB::MySQL::addTransaction(const DB::Transaction& transaction) { add.execute(); result.id = lastInsertedId(); - //todo retreive timestamp and actual value which could have changed after insertion + std::chrono::time_point currently = std::chrono::time_point_cast( + std::chrono::system_clock::now() + ); + result.modified = currently.time_since_epoch().count(); + //todo actual value which could have changed after insertion return result; } void DB::MySQL::updateTransaction(const DB::Transaction& transaction) { + MYSQL* con = &connection; + DB::Transaction result = transaction; + + std::string value = std::to_string(result.value); + + Statement upd(con, updateTransactionQuery); + upd.bind(&result.initiator, MYSQL_TYPE_LONG, true); + upd.bind(&result.asset, MYSQL_TYPE_LONG, true); + upd.bind(&result.parent, MYSQL_TYPE_LONG, true); + upd.bind(value.data(), MYSQL_TYPE_STRING); + upd.bind(&result.performed, MYSQL_TYPE_LONG, true); + upd.bind(&result.id, MYSQL_TYPE_LONG, true); + upd.execute(); } std::vector DB::MySQL::listTransactions(uint32_t owner) { diff --git a/database/mysql/mysql.h b/database/mysql/mysql.h index 273a9e8..2bc92e4 100644 --- a/database/mysql/mysql.h +++ b/database/mysql/mysql.h @@ -49,7 +49,7 @@ public: private: void executeFile (const std::filesystem::path& relativePath); - static std::optional getComment (std::string& string); + bool getBlock (std::ifstream& file, std::string& block, std::string& name); uint32_t lastInsertedId (); protected: