// // Created by Иван_Архипов on 17.11.2017. // #include "Database.h" #include "BinaryData.h" #include "SubfileData.h" #include "EasyLogging++/easylogging++.h" namespace LOTRO_DAT { Database::Database() { LOG(DEBUG) << "Initialising new Database instance."; db_ = nullptr; } bool Database::CloseDatabase() { LOG(DEBUG) << "Closing database."; if (db_ != nullptr) { ExecSql("COMMIT TRANSACTION"); sqlite3_finalize(insert_request_); sqlite3_finalize(fetch_one_request_); sqlite3_finalize(get_rows_number_request_); if (sqlite3_close_v2(db_) != SQLITE_OK) LOG(ERROR) << "Database error when closing: " << sqlite3_errmsg(db_); db_ = nullptr; } LOG(DEBUG) << "Database successfully closed."; return true; } Database::~Database() { CloseDatabase(); } bool Database::InitDatabase(const std::string &filename) { LOG(DEBUG) << "Initializing database " << filename; CloseDatabase(); if (sqlite3_open(filename.c_str(), &db_) != SQLITE_OK) { sqlite3_close(db_); db_ = nullptr; LOG(ERROR) << "sqlite3_open returned an error. Unable to open file " << filename; return false; } ExecSql("PRAGMA synchronous = OFF"); ExecSql("PRAGMA count_changes = OFF"); ExecSql("PRAGMA journal_mode = MEMORY"); ExecSql("PRAGMA temp_store = MEMORY"); ExecSql("PRAGMA encoding = \"UTF-8\";"); ExecSql(CreateTableCommand_); sqlite3_prepare_v2(db_, InsertFileCommand_.c_str(), InsertFileCommand_.length(), &insert_request_, nullptr); sqlite3_prepare_v2(db_, FetchOneCommand.c_str(), FetchOneCommand.length(), &fetch_one_request_, nullptr); sqlite3_prepare_v2(db_, GetRowsNumberCommand_.c_str(), GetRowsNumberCommand_.length(), &get_rows_number_request_, nullptr); ExecSql("BEGIN TRANSACTION"); LOG(DEBUG) << "Database " << filename << " successfully initialized"; return true; } void Database::ExecSql(const std::string &sql) { LOG(DEBUG) << "Executing SQL request: " << sql; if (db_ == nullptr) { LOG(WARNING) << "Trying to execute sql query to db, which hasn't been opened yet."; return; } char *error; if (sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, &error) != SQLITE_OK) { LOG(ERROR) << "SQLite3 error: " << sqlite3_errmsg(db_); return; } LOG(DEBUG) << "SQL request " << sql << " executed successfully"; } bool Database::PushFile(const SubfileData &data) { LOG(DEBUG) << "Pushing to database file with file_id " << data.options["fid"].as(); if (db_ == nullptr) { LOG(WARNING) << "Trying to push file to db, which hasn't been opened yet."; return false; } std::stringstream options_; options_ << data.options; sqlite3_bind_blob(insert_request_, 1, data.binary_data.data(), data.binary_data.size(), SQLITE_TRANSIENT); sqlite3_bind_text16(insert_request_, 2, data.text_data.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(insert_request_, 3, options_.str().c_str(), -1, SQLITE_TRANSIENT); if (sqlite3_step(insert_request_) != SQLITE_DONE) { LOG(ERROR) << "SQLite3 error: " << sqlite3_errmsg(db_); return false; } sqlite3_reset(insert_request_); LOG(DEBUG) << "File with file_id " << data.options["fid"].as() << " pushed to database successfully."; return true; } SubfileData Database::GetNextFile() { LOG(DEBUG) << "Getting next file from database.."; if (db_ == nullptr) { LOG(WARNING) << "Trying to get next file from db, which hasn't been opened yet."; return SubfileData(); } SubfileData data; int result = sqlite3_step(fetch_one_request_); if (result == SQLITE_ROW) { data.binary_data = BinaryData((char *) sqlite3_column_blob(fetch_one_request_, 0), unsigned(sqlite3_column_bytes(fetch_one_request_, 0))); data.text_data = std::u16string((char16_t *) sqlite3_column_text16(fetch_one_request_, 1)); std::string _options = std::string((char *) sqlite3_column_text(fetch_one_request_, 2), unsigned(sqlite3_column_bytes(fetch_one_request_, 2))); data.options = YAML::Load(_options); return data; } if (result == SQLITE_DONE) { LOG(DEBUG) << "Next file fetched successfully."; return data; } LOG(ERROR) << "SQLite3 fetch_one request returned " << result << " code. SQLite message is: "<< sqlite3_errmsg(db_); return data; } size_t Database::CountRows() { LOG(INFO) << "Counting rows in database..."; if (db_ == nullptr) { LOG(WARNING) << "Trying to execute sql query (Count rows) to db, which hasn't been opened yet."; return 0; } int result = sqlite3_step(get_rows_number_request_); if (result == SQLITE_ERROR) { LOG(ERROR) << "Error when counting rows " << sqlite3_errmsg(db_); return 0; } long long res = sqlite3_column_int64(get_rows_number_request_, 0); sqlite3_reset(get_rows_number_request_); LOG(INFO) << "Counted " << size_t(res) << " rows in database."; return size_t(res); } }