#include #ifdef SQLITE3_FOUND #include #include #include #include #include #include #include #include Sqlite3Engine::Sqlite3Engine(sqlite3* db): db(db) { } Sqlite3Engine::~Sqlite3Engine() { sqlite3_close(this->db); } std::map Sqlite3Engine::get_all_columns_from_table(const std::string& table_name) { std::map result; char* errmsg; std::string query{"PRAGMA table_info(" + table_name + ")"}; int res = sqlite3_exec(this->db, query.data(), [](void* param, int columns_nb, char** columns, char**) -> int { constexpr int name_column = 1; constexpr int data_type_column = 2; auto* result = static_cast*>(param); if (name_column < columns_nb && data_type_column < columns_nb) (*result)[utils::tolower(columns[name_column])] = utils::tolower(columns[data_type_column]); return 0; }, &result, &errmsg); if (res != SQLITE_OK) { log_error("Error executing ", query, ": ", errmsg); sqlite3_free(errmsg); } return result; } template static auto make_select_query(const Row&, const std::string& name) { return SelectQuery{name}; } void Sqlite3Engine::convert_date_format(DatabaseEngine& db) { Transaction transaction{}; auto rollback = [&transaction] (const std::string& error_msg) { log_error("Failed to execute query: ", error_msg); transaction.rollback(); }; const auto real_name = Database::muc_log_lines.get_name(); const auto tmp_name = real_name + "tmp_"; const std::string date_name = Database::Date::name; auto result = db.raw_exec("ALTER TABLE " + real_name + " RENAME TO " + tmp_name); if (!std::get(result)) return rollback(std::get(result)); Database::muc_log_lines.create(db); Database::OldMucLogLineTable old_muc_log_line(tmp_name); auto select_query = make_select_query(old_muc_log_line.row(), old_muc_log_line.get_name()); auto& select_body = select_query.body; auto begin = select_body.find(date_name); select_body.replace(begin, date_name.size(), "julianday("+date_name+", 'unixepoch')"); select_body = "INSERT INTO " + real_name + " " + select_body; result = db.raw_exec(select_body); if (!std::get(result)) return rollback(std::get(result)); result = db.raw_exec("DROP TABLE " + tmp_name); if (!std::get(result)) return rollback(std::get(result)); } std::unique_ptr Sqlite3Engine::open(const std::string& filename) { sqlite3* new_db; auto res = sqlite3_open_v2(filename.data(), &new_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr); if (res != SQLITE_OK) { log_error("Failed to open database file ", filename, ": ", sqlite3_errmsg(new_db)); sqlite3_close(new_db); throw std::runtime_error(""); } return std::make_unique(new_db); } std::tuple Sqlite3Engine::raw_exec(const std::string& query) { #ifdef DEBUG_SQL_QUERIES log_debug("SQL QUERY: ", query); const auto timer = make_sql_timer(); #endif char* error; const auto result = sqlite3_exec(db, query.data(), nullptr, nullptr, &error); if (result != SQLITE_OK) { std::string err_msg(error); sqlite3_free(error); return std::make_tuple(false, err_msg); } return std::make_tuple(true, std::string{}); } std::unique_ptr Sqlite3Engine::prepare(const std::string& query) { sqlite3_stmt* stmt; auto res = sqlite3_prepare(db, query.data(), static_cast(query.size()) + 1, &stmt, nullptr); if (res != SQLITE_OK) { log_error("Error preparing statement: ", sqlite3_errmsg(db)); return nullptr; } return std::make_unique(stmt); } void Sqlite3Engine::extract_last_insert_rowid(Statement&) { this->last_inserted_rowid = sqlite3_last_insert_rowid(this->db); } std::string Sqlite3Engine::id_column_type() const { return "INTEGER PRIMARY KEY AUTOINCREMENT"; } std::string Sqlite3Engine::datetime_column_type() const { return "REAL"; } long double Sqlite3Engine::epoch_to_floating_value(long double d) const { return (d / 86400.0) + 2440587.5; } #endif