Database.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. //
  2. // Created by Иван_Архипов on 17.11.2017.
  3. //
  4. #include "Database.h"
  5. #include "DatException.h"
  6. #include "BinaryData.h"
  7. #include "SubfileData.h"
  8. #include "EasyLogging++/easylogging++.h"
  9. namespace LOTRO_DAT {
  10. Database::Database() {
  11. LOG(DEBUG) << "Initialising new Database instance.";
  12. db_ = nullptr;
  13. }
  14. bool Database::CloseDatabase() {
  15. LOG(DEBUG) << "Closing database.";
  16. try {
  17. if (db_ != nullptr) {
  18. ExecSql("COMMIT TRANSACTION");
  19. sqlite3_finalize(insert_request_);
  20. sqlite3_finalize(fetch_one_request_);
  21. sqlite3_finalize(get_rows_number_request_);
  22. if (sqlite3_close_v2(db_) != SQLITE_OK)
  23. LOG(ERROR) << "Database error when closing: " << sqlite3_errmsg(db_);
  24. db_ = nullptr;
  25. }
  26. } catch (std::exception &e) {
  27. LOG(ERROR) << "caught " << e.what() << " exception";
  28. return false;
  29. }
  30. LOG(DEBUG) << "Database successfully closed.";
  31. return true;
  32. }
  33. Database::~Database() {
  34. CloseDatabase();
  35. }
  36. bool Database::InitDatabase(const std::string &filename) {
  37. LOG(DEBUG) << "Initializing database " << filename;
  38. try {
  39. CloseDatabase();
  40. if (sqlite3_open(filename.c_str(), &db_) != SQLITE_OK) {
  41. sqlite3_close(db_);
  42. LOG(ERROR) << "sqlite3_open returned an error.";
  43. throw DatException("Bad Database::InitDatabase() - sqlite3_open returned an error...",
  44. DATABASE_EXCEPTION);
  45. }
  46. ExecSql("PRAGMA synchronous = OFF");
  47. ExecSql("PRAGMA count_changes = OFF");
  48. ExecSql("PRAGMA journal_mode = MEMORY");
  49. ExecSql("PRAGMA temp_store = MEMORY");
  50. ExecSql("PRAGMA encoding = \"UTF-8\";");
  51. ExecSql(CreateTableCommand_);
  52. sqlite3_prepare_v2(db_, InsertFileCommand_.c_str(), InsertFileCommand_.length(), &insert_request_, nullptr);
  53. sqlite3_prepare_v2(db_, FetchOneCommand.c_str(), FetchOneCommand.length(), &fetch_one_request_, nullptr);
  54. sqlite3_prepare_v2(db_, GetRowsNumberCommand_.c_str(), GetRowsNumberCommand_.length(),
  55. &get_rows_number_request_, nullptr);
  56. ExecSql("BEGIN TRANSACTION");
  57. } catch (std::exception &e) {
  58. LOG(ERROR) << "Caught " << e.what() << " exception.";
  59. return false;
  60. }
  61. LOG(DEBUG) << "Database " << filename << " successfully initialized";
  62. return true;
  63. }
  64. void Database::ExecSql(const std::string &sql) {
  65. LOG(DEBUG) << "Executing SQL request: " << sql;
  66. if (db_ == nullptr) {
  67. LOG(WARNING) << "Trying to execute sql query to db, which hasn't been opened yet.";
  68. return;
  69. }
  70. char *error;
  71. if (sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, &error) != SQLITE_OK) {
  72. LOG(ERROR) << "SQLite3 error: " << sqlite3_errmsg(db_);
  73. return;
  74. }
  75. LOG(DEBUG) << "SQL request " << sql << " executed successfully";
  76. }
  77. bool Database::PushFile(const SubfileData &data) {
  78. LOG(DEBUG) << "Pushing to database file with file_id " << data.options["fid"].as<long long>();
  79. try {
  80. if (db_ == nullptr) {
  81. LOG(WARNING) << "Trying to execute sql query to db, which hasn't been opened yet.";
  82. return false;
  83. }
  84. std::stringstream options_;
  85. options_ << data.options;
  86. sqlite3_bind_blob(insert_request_, 1, data.binary_data.data(), data.binary_data.size(), SQLITE_TRANSIENT);
  87. sqlite3_bind_text16(insert_request_, 2, data.text_data.c_str(), -1, SQLITE_TRANSIENT);
  88. sqlite3_bind_text(insert_request_, 3, options_.str().c_str(), -1, SQLITE_TRANSIENT);
  89. if (sqlite3_step(insert_request_) != SQLITE_DONE) {
  90. LOG(ERROR) << "SQLite3 error: " << sqlite3_errmsg(db_);
  91. return false;
  92. }
  93. sqlite3_reset(insert_request_);
  94. } catch (std::exception &e) {
  95. LOG(ERROR) << "Caught " << e.what() << " exception";
  96. return false;
  97. }
  98. LOG(DEBUG) << "File with file_id " << data.options["fid"].as<long long>() << " pushed to database successfully.";
  99. return true;
  100. }
  101. SubfileData Database::GetNextFile() {
  102. LOG(DEBUG) << "Getting next file from database..";
  103. try {
  104. SubfileData data;
  105. if (db_ == nullptr) {
  106. LOG(WARNING) << "Trying to execute sql query to db, which hasn't been opened yet.";
  107. return data;
  108. }
  109. int result = sqlite3_step(fetch_one_request_);
  110. if (result == SQLITE_ROW) {
  111. data.binary_data = BinaryData((char *) sqlite3_column_blob(fetch_one_request_, 0),
  112. unsigned(sqlite3_column_bytes(fetch_one_request_, 0)));
  113. data.text_data = std::u16string((char16_t *) sqlite3_column_text16(fetch_one_request_, 1));
  114. std::string _options = std::string((char *) sqlite3_column_text(fetch_one_request_, 2),
  115. unsigned(sqlite3_column_bytes(fetch_one_request_, 2)));
  116. data.options = YAML::Load(_options);
  117. return data;
  118. }
  119. if (result == SQLITE_DONE) {
  120. LOG(DEBUG) << "Next file fetched successfully.";
  121. return data;
  122. }
  123. LOG(ERROR) << "SQLite3 fetch_one request returned " << result << " code. SQLite message is: "<< sqlite3_errmsg(db_);
  124. return data;
  125. } catch (std::exception &e) {
  126. LOG(ERROR) << "Caught " << e.what() << " exception.";
  127. return SubfileData();
  128. }
  129. }
  130. bool Database::RemoveDatabase() {
  131. try {
  132. if (db_ == nullptr)
  133. throw DatException("Bad Database::RemoveDatabase() - database hasn't been opened!", DATABASE_EXCEPTION);
  134. throw DatException("Database::RemoveDatabase() haven't been implemented yet...", DATABASE_EXCEPTION);
  135. // TODO: Implement function
  136. } catch (std::exception &e) {
  137. fprintf(stderr, "Bad Database::RemoveDatabase() - caught exception %s\n", e.what());
  138. return false;
  139. }
  140. }
  141. bool Database::ClearDatabase() {
  142. try {
  143. if (db_ == nullptr)
  144. throw DatException("Bad Database::ClearDatabase() - database hasn't been opened!", DATABASE_EXCEPTION);
  145. ExecSql(ClearTableCommand_);
  146. return true;
  147. } catch (std::exception &e) {
  148. fprintf(stderr, "Bad Database::ClearDatabase() - caught exception %s\n", e.what());
  149. return false;
  150. }
  151. }
  152. size_t Database::CountRows() {
  153. LOG(INFO) << "Counting rows in database...";
  154. try {
  155. if (db_ == nullptr) {
  156. LOG(WARNING) << "Trying to execute sql query to db, which hasn't been opened yet.";
  157. return 0;
  158. }
  159. int result = sqlite3_step(get_rows_number_request_);
  160. if (result == SQLITE_ERROR) {
  161. LOG(ERROR) << "Error when counting rows " << sqlite3_errmsg(db_);
  162. return 0;
  163. }
  164. long long res = sqlite3_column_int64(get_rows_number_request_, 0);
  165. sqlite3_reset(get_rows_number_request_);
  166. LOG(INFO) << "Counted " << size_t(res) << " rows in database.";
  167. return size_t(res);
  168. } catch (std::exception &e) {
  169. LOG(ERROR) << "Caught " << e.what() << "exception.";
  170. return 0;
  171. }
  172. }
  173. }