rssguard/src/librssguard/database/databasedriver.cpp
2023-01-04 14:11:23 +01:00

108 lines
4.6 KiB
C++

// For license of this file, see <project-root-folder>/LICENSE.md.
#include "database/databasedriver.h"
#include "definitions/definitions.h"
#include "exceptions/ioexception.h"
#include "miscellaneous/iofactory.h"
#include <QDir>
#include <QRegularExpression>
#include <QSqlError>
#include <QSqlQuery>
#include <QThread>
DatabaseDriver::DatabaseDriver(QObject* parent) : QObject(parent) {}
QSqlDatabase DatabaseDriver::threadSafeConnection(const QString& connection_name, DesiredStorageType desired_type) {
qlonglong thread_id = qlonglong(QThread::currentThreadId());
bool is_main_thread = QThread::currentThread() == qApp->thread();
QSqlDatabase database =
connection(is_main_thread ? connection_name : QSL("db_connection_%1").arg(thread_id), desired_type);
return database;
}
void DatabaseDriver::updateDatabaseSchema(QSqlQuery& query,
int source_db_schema_version,
const QString& database_name) {
const int current_version = QSL(APP_DB_SCHEMA_VERSION).toInt();
while (source_db_schema_version != current_version) {
const QStringList statements = prepareScript(APP_SQL_PATH,
QSL(APP_DB_UPDATE_FILE_PATTERN)
.arg(ddlFilePrefix(),
QString::number(source_db_schema_version),
QString::number(source_db_schema_version + 1)),
database_name);
for (const QString& statement : statements) {
if (!query.exec(statement) && query.lastError().isValid()) {
throw ApplicationException(query.lastError().text());
}
}
// Increment the version.
qDebugNN << LOGSEC_DB << "Updating database schema " << QUOTE_W_SPACE(source_db_schema_version) << "->"
<< QUOTE_W_SPACE_DOT(source_db_schema_version + 1);
source_db_schema_version++;
}
setSchemaVersion(query, current_version, false);
}
void DatabaseDriver::setSchemaVersion(QSqlQuery& query, int new_schema_version, bool empty_table) {
if (!query.prepare(empty_table
? QSL("INSERT INTO Information VALUES ('schema_version', :schema_version);")
: QSL("UPDATE Information SET inf_value = :schema_version WHERE inf_key = 'schema_version';"))) {
throw ApplicationException(query.lastError().text());
}
query.bindValue(QSL(":schema_version"), QString::number(new_schema_version));
if (!query.exec()) {
throw ApplicationException(query.lastError().text());
}
}
QStringList DatabaseDriver::prepareScript(const QString& base_sql_folder,
const QString& sql_file,
const QString& database_name) {
QStringList statements;
QString next_file = base_sql_folder + QDir::separator() + sql_file;
QString sql_script = QString::fromUtf8(IOFactory::readFile(next_file));
QStringList new_statements = sql_script.split(QSL(APP_DB_COMMENT_SPLIT),
#if QT_VERSION >= 0x050F00 // Qt >= 5.15.0
Qt::SplitBehaviorFlags::SkipEmptyParts);
#else
QString::SplitBehavior::SkipEmptyParts);
#endif
for (int i = 0; i < new_statements.size(); i++) {
if (new_statements.at(i).startsWith(QSL(APP_DB_INCLUDE_PLACEHOLDER))) {
// We include another file.
QString included_file_name = new_statements.at(i).mid(QSL(APP_DB_INCLUDE_PLACEHOLDER).size() + 1).simplified();
QString included_file = base_sql_folder + QDir::separator() + included_file_name;
QString included_sql_script = QString::fromUtf8(IOFactory::readFile(included_file));
QStringList included_statements = included_sql_script.split(QSL(APP_DB_COMMENT_SPLIT),
#if QT_VERSION >= 0x050F00 // Qt >= 5.15.0
Qt::SplitBehaviorFlags::SkipEmptyParts);
#else
QString::SplitBehavior::SkipEmptyParts);
#endif
statements << included_statements;
}
else {
statements << new_statements.at(i);
}
}
statements = statements.replaceInStrings(QSL(APP_DB_NAME_PLACEHOLDER), database_name);
statements = statements.replaceInStrings(QSL(APP_DB_AUTO_INC_PRIM_KEY_PLACEHOLDER), autoIncrementPrimaryKey());
statements = statements.replaceInStrings(QSL(APP_DB_BLOB_PLACEHOLDER), blob());
return statements;
}