set DB schema version programmatically in a centralized way, use exceptions when things go wrong

This commit is contained in:
Martin Rotter 2022-02-02 08:43:45 +01:00
parent 392ff2415f
commit 46f3e25e92
6 changed files with 45 additions and 37 deletions

View file

@ -3,8 +3,6 @@ CREATE TABLE Information (
inf_value TEXT inf_value TEXT
); );
-- ! -- !
INSERT INTO Information VALUES ('schema_version', '2');
-- !
CREATE TABLE Accounts ( CREATE TABLE Accounts (
id $$, id $$,
type TEXT NOT NULL CHECK (type != ''), /* ID of the account type. Each account defines its own, for example 'ttrss'. */ type TEXT NOT NULL CHECK (type != ''), /* ID of the account type. Each account defines its own, for example 'ttrss'. */

View file

@ -26,6 +26,4 @@ INSERT INTO Feeds (id, title, description, date_created, icon, category, source,
SELECT id, title, description, date_created, icon, category, source, update_type, update_interval, account_id, custom_id, custom_data SELECT id, title, description, date_created, icon, category, source, update_type, update_interval, account_id, custom_id, custom_data
FROM backup_Feeds; FROM backup_Feeds;
-- ! -- !
DROP TABLE backup_Feeds; DROP TABLE backup_Feeds;
-- !
UPDATE Information SET inf_value = '2' WHERE inf_key = 'schema_version';

View file

@ -14,28 +14,23 @@
DatabaseDriver::DatabaseDriver(QObject* parent) : QObject(parent) DatabaseDriver::DatabaseDriver(QObject* parent) : QObject(parent)
{} {}
bool DatabaseDriver::updateDatabaseSchema(QSqlQuery& query, void DatabaseDriver::updateDatabaseSchema(QSqlQuery& query,
int source_db_schema_version, int source_db_schema_version,
const QString& database_name) { const QString& database_name) {
const int current_version = QSL(APP_DB_SCHEMA_VERSION).toInt(); const int current_version = QSL(APP_DB_SCHEMA_VERSION).toInt();
while (source_db_schema_version != current_version) { while (source_db_schema_version != current_version) {
try { const QStringList statements = prepareScript(APP_SQL_PATH,
const QStringList statements = prepareScript(APP_SQL_PATH, QSL(APP_DB_UPDATE_FILE_PATTERN).arg(ddlFilePrefix(),
QSL(APP_DB_UPDATE_FILE_PATTERN).arg(ddlFilePrefix(), QString::number(source_db_schema_version),
QString::number(source_db_schema_version), QString::number(source_db_schema_version + 1)),
QString::number(source_db_schema_version + 1)), database_name);
database_name);
for (const QString& statement : statements) { for (const QString& statement : statements) {
if (!query.exec(statement) && query.lastError().isValid()) { if (!query.exec(statement) && query.lastError().isValid()) {
throw ApplicationException(query.lastError().text()); throw ApplicationException(query.lastError().text());
}
} }
} }
catch (const ApplicationException& ex) {
qFatal("Error when running SQL scripts: %s.", qPrintable(ex.message()));
}
// Increment the version. // Increment the version.
qDebugNN << LOGSEC_DB qDebugNN << LOGSEC_DB
@ -47,7 +42,20 @@ bool DatabaseDriver::updateDatabaseSchema(QSqlQuery& query,
source_db_schema_version++; source_db_schema_version++;
} }
return true; 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, QStringList DatabaseDriver::prepareScript(const QString& base_sql_folder,

View file

@ -46,10 +46,12 @@ class DatabaseDriver : public QObject {
DatabaseDriver::DesiredStorageType desired_type = DatabaseDriver::DesiredStorageType::FromSettings) = 0; DatabaseDriver::DesiredStorageType desired_type = DatabaseDriver::DesiredStorageType::FromSettings) = 0;
protected: protected:
bool updateDatabaseSchema(QSqlQuery& query, void updateDatabaseSchema(QSqlQuery& query,
int source_db_schema_version, int source_db_schema_version,
const QString& database_name = {}); const QString& database_name = {});
void setSchemaVersion(QSqlQuery& query, int new_schema_version, bool empty_table);
QStringList prepareScript(const QString& base_sql_folder, QStringList prepareScript(const QString& base_sql_folder,
const QString& sql_file, const QString& sql_file,
const QString& database_name = {}); const QString& database_name = {});

View file

@ -183,6 +183,8 @@ QSqlDatabase MariaDbDriver::initializeDatabase(const QString& connection_name) {
throw ApplicationException(query_db.lastError().text()); throw ApplicationException(query_db.lastError().text());
} }
} }
setSchemaVersion(query_db, QSL(APP_DB_SCHEMA_VERSION).toInt(), true);
} }
catch (const ApplicationException& ex) { catch (const ApplicationException& ex) {
qFatal("Error when running SQL scripts: %s.", qPrintable(ex.message())); qFatal("Error when running SQL scripts: %s.", qPrintable(ex.message()));
@ -196,18 +198,17 @@ QSqlDatabase MariaDbDriver::initializeDatabase(const QString& connection_name) {
const int installed_db_schema = query_db.value(0).toString().toInt(); const int installed_db_schema = query_db.value(0).toString().toInt();
if (installed_db_schema < QSL(APP_DB_SCHEMA_VERSION).toInt()) { if (installed_db_schema < QSL(APP_DB_SCHEMA_VERSION).toInt()) {
if (updateDatabaseSchema(query_db, installed_db_schema, database_name)) { try {
updateDatabaseSchema(query_db, installed_db_schema, database_name);
qDebugNN << LOGSEC_DB qDebugNN << LOGSEC_DB
<< "Database schema was updated from" << "Database schema was updated from"
<< QUOTE_W_SPACE(installed_db_schema) << QUOTE_W_SPACE(installed_db_schema)
<< "to" << "to"
<< QUOTE_W_SPACE(APP_DB_SCHEMA_VERSION) << QUOTE_W_SPACE(APP_DB_SCHEMA_VERSION)
<< "successully or it is already up to date."; << "successully.";
} }
else { catch (const ApplicationException& ex) {
qFatal("Database schema was not updated from '%s' to '%s' successully.", qFatal("Error when updating DB schema from %d: %s.", installed_db_schema, qPrintable(ex.message()));
qPrintable(QString::number(installed_db_schema)),
APP_DB_SCHEMA_VERSION);
} }
} }
} }

View file

@ -254,6 +254,8 @@ QSqlDatabase SqliteDriver::initializeDatabase(const QString& connection_name, bo
throw ApplicationException(query_db.lastError().text()); throw ApplicationException(query_db.lastError().text());
} }
} }
setSchemaVersion(query_db, QSL(APP_DB_SCHEMA_VERSION).toInt(), true);
} }
catch (const ApplicationException& ex) { catch (const ApplicationException& ex) {
qFatal("Error when running SQL scripts: %s.", qPrintable(ex.message())); qFatal("Error when running SQL scripts: %s.", qPrintable(ex.message()));
@ -274,18 +276,17 @@ QSqlDatabase SqliteDriver::initializeDatabase(const QString& connection_name, bo
qFatal("Creation of backup SQLite DB file failed."); qFatal("Creation of backup SQLite DB file failed.");
} }
if (updateDatabaseSchema(query_db, installed_db_schema)) { try {
updateDatabaseSchema(query_db, installed_db_schema);
qDebugNN << LOGSEC_DB qDebugNN << LOGSEC_DB
<< "Database schema was updated from '" << "Database schema was updated from"
<< installed_db_schema << QUOTE_W_SPACE(installed_db_schema)
<< "' to '" << "to"
<< APP_DB_SCHEMA_VERSION << QUOTE_W_SPACE(APP_DB_SCHEMA_VERSION)
<< "' successully or it is already up to date."; << "successully.";
} }
else { catch (const ApplicationException& ex) {
qFatal("Database schema was not updated from '%s' to '%s' successully.", qFatal("Error when updating DB schema from %d: %s.", installed_db_schema, qPrintable(ex.message()));
qPrintable(QString::number(installed_db_schema)),
APP_DB_SCHEMA_VERSION);
} }
} }