database.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #include "database.h"
  2. #include "binarydata.h"
  3. #include "subfiledata.h"
  4. #include <EasyLogging++/easylogging++.h>
  5. #include <SQLite/lotrodat_sqlite3.h>
  6. #include <yaml-cpp/yaml.h>
  7. #ifdef _WIN32
  8. #include <io.h>
  9. #define access _access_s
  10. #else
  11. #include <unistd.h>
  12. #endif
  13. namespace LOTRO_DAT {
  14. Database::Database() {
  15. LOG(DEBUG) << "Initialising new Database instance.";
  16. db_ = nullptr;
  17. }
  18. bool Database::CloseDatabase() {
  19. if (db_ == nullptr) {
  20. return true;
  21. }
  22. LOG(DEBUG) << "Closing database.";
  23. ExecSql("COMMIT TRANSACTION");
  24. lotrodat_sqlite3_finalize(insert_request_);
  25. lotrodat_sqlite3_finalize(fetch_one_request_);
  26. lotrodat_sqlite3_finalize(get_rows_number_request_);
  27. if (lotrodat_sqlite3_close_v2(db_) != SQLITE_OK)
  28. LOG(ERROR) << "Database error when closing: " <<lotrodat_sqlite3_errmsg(db_);
  29. db_ = nullptr;
  30. LOG(DEBUG) << "Database successfully closed.";
  31. return true;
  32. }
  33. Database::~Database() {
  34. CloseDatabase();
  35. }
  36. bool Database::InitDatabase(const std::string &filename, bool create_if_not_exists) {
  37. LOG(DEBUG) << "Initializing database " << filename;
  38. if (!create_if_not_exists && access(filename.c_str(), 0 ) != 0) {
  39. LOG(ERROR) << "Cannot init database: file with name " << filename << " does not exist!";
  40. return false;
  41. }
  42. CloseDatabase();
  43. if (lotrodat_sqlite3_open(filename.c_str(), &db_) != SQLITE_OK) {
  44. lotrodat_sqlite3_close(db_);
  45. db_ = nullptr;
  46. LOG(ERROR) << "sqlite3_open returned an error. Unable to open file " << filename;
  47. return false;
  48. }
  49. ExecSql("PRAGMA synchronous = OFF");
  50. ExecSql("PRAGMA count_changes = OFF");
  51. ExecSql("PRAGMA journal_mode = MEMORY");
  52. ExecSql("PRAGMA temp_store = MEMORY");
  53. ExecSql("PRAGMA encoding = \"UTF-8\";");
  54. ExecSql(CreateTableCommand_);
  55. lotrodat_sqlite3_prepare_v2(db_, InsertFileCommand_.c_str(), InsertFileCommand_.length(), &insert_request_, nullptr);
  56. lotrodat_sqlite3_prepare_v2(db_, FetchOneCommand.c_str(), FetchOneCommand.length(), &fetch_one_request_, nullptr);
  57. lotrodat_sqlite3_prepare_v2(db_, GetRowsNumberCommand_.c_str(), GetRowsNumberCommand_.length(),
  58. &get_rows_number_request_, nullptr);
  59. ExecSql("BEGIN TRANSACTION");
  60. LOG(DEBUG) << "Database " << filename << " successfully initialized";
  61. return true;
  62. }
  63. void Database::ExecSql(const std::string &sql) {
  64. LOG(DEBUG) << "Executing SQL request: " << sql;
  65. if (db_ == nullptr) {
  66. LOG(WARNING) << "Trying to execute sql query to db, which hasn't been opened yet.";
  67. return;
  68. }
  69. char *error;
  70. if (lotrodat_sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, &error) != SQLITE_OK) {
  71. LOG(ERROR) << "SQLite3 error: " << lotrodat_sqlite3_errmsg(db_);
  72. return;
  73. }
  74. LOG(DEBUG) << "SQL request " << sql << " executed successfully";
  75. }
  76. bool Database::PushFile(const SubfileData &data) {
  77. LOG(DEBUG) << "Pushing to database file with file_id " << data.options["fid"].as<long long>();
  78. if (db_ == nullptr) {
  79. LOG(WARNING) << "Trying to push file to db, which hasn't been opened yet.";
  80. return false;
  81. }
  82. std::stringstream options_;
  83. options_ << data.options;
  84. lotrodat_sqlite3_bind_blob(insert_request_, 1, data.binary_data.data(), data.binary_data.size(), SQLITE_TRANSIENT);
  85. lotrodat_sqlite3_bind_text16(insert_request_, 2, data.text_data.c_str(), -1, SQLITE_TRANSIENT);
  86. lotrodat_sqlite3_bind_text(insert_request_, 3, options_.str().c_str(), -1, SQLITE_TRANSIENT);
  87. if (lotrodat_sqlite3_step(insert_request_) != SQLITE_DONE) {
  88. LOG(ERROR) << "SQLite3 error: " << lotrodat_sqlite3_errmsg(db_);
  89. return false;
  90. }
  91. lotrodat_sqlite3_reset(insert_request_);
  92. LOG(DEBUG) << "File with file_id " << data.options["fid"].as<long long>() << " pushed to database successfully.";
  93. return true;
  94. }
  95. SubfileData Database::GetNextFile() {
  96. LOG(DEBUG) << "Getting next file from database..";
  97. if (db_ == nullptr) {
  98. LOG(WARNING) << "Trying to get next file from db, which hasn't been opened yet.";
  99. return SubfileData();
  100. }
  101. SubfileData data;
  102. int result = lotrodat_sqlite3_step(fetch_one_request_);
  103. if (result == SQLITE_ROW) {
  104. data.binary_data = BinaryData((char *) lotrodat_sqlite3_column_blob(fetch_one_request_, 0),
  105. unsigned(lotrodat_sqlite3_column_bytes(fetch_one_request_, 0)));
  106. data.text_data = std::u16string((char16_t *) lotrodat_sqlite3_column_text16(fetch_one_request_, 1));
  107. std::string _options = std::string((char *) lotrodat_sqlite3_column_text(fetch_one_request_, 2),
  108. unsigned(lotrodat_sqlite3_column_bytes(fetch_one_request_, 2)));
  109. data.options = YAML::Load(_options);
  110. return data;
  111. }
  112. if (result == SQLITE_DONE) {
  113. LOG(DEBUG) << "Next file fetched successfully.";
  114. return data;
  115. }
  116. LOG(ERROR) << "SQLite3 fetch_one request returned " << result << " code. SQLite message is: "<< lotrodat_sqlite3_errmsg(db_);
  117. return data;
  118. }
  119. size_t Database::CountRows() {
  120. LOG(INFO) << "Counting rows in database...";
  121. if (db_ == nullptr) {
  122. LOG(WARNING) << "Trying to execute sql query (Count rows) to db, which hasn't been opened yet.";
  123. return 0;
  124. }
  125. int result = lotrodat_sqlite3_step(get_rows_number_request_);
  126. if (result == SQLITE_ERROR) {
  127. LOG(ERROR) << "Error when counting rows " << lotrodat_sqlite3_errmsg(db_);
  128. return 0;
  129. }
  130. long long res = lotrodat_sqlite3_column_int64(get_rows_number_request_, 0);
  131. lotrodat_sqlite3_reset(get_rows_number_request_);
  132. LOG(INFO) << "Counted " << size_t(res) << " rows in database.";
  133. return size_t(res);
  134. }
  135. } // namespace LOTRO_DAT