mirror of
https://github.com/YACReader/yacreader
synced 2025-11-16 06:52:46 -05:00
Make sure DB upgrades happen atomically
This commit is contained in:
@ -901,224 +901,229 @@ bool DataBaseManagement::updateToCurrentVersion(const QString &libraryPath)
|
|||||||
{
|
{
|
||||||
QSqlDatabase db = loadDatabaseFromFile(libraryDatabasePath);
|
QSqlDatabase db = loadDatabaseFromFile(libraryDatabasePath);
|
||||||
if (db.isValid() && db.isOpen()) {
|
if (db.isValid() && db.isOpen()) {
|
||||||
if (pre7) // TODO: execute only if previous version was < 7.0
|
if (!db.transaction()) {
|
||||||
{
|
QLOG_ERROR() << "Failed to start transaction for database update";
|
||||||
// new 7.0 fields
|
returnValue = false;
|
||||||
QStringList columnDefs;
|
} else {
|
||||||
columnDefs << "hasBeenOpened BOOLEAN DEFAULT 0"
|
if (pre7) {
|
||||||
<< "rating INTEGER DEFAULT 0"
|
// new 7.0 fields
|
||||||
<< "currentPage INTEGER DEFAULT 1"
|
|
||||||
<< "bookmark1 INTEGER DEFAULT -1"
|
|
||||||
<< "bookmark2 INTEGER DEFAULT -1"
|
|
||||||
<< "bookmark3 INTEGER DEFAULT -1"
|
|
||||||
<< "brightness INTEGER DEFAULT -1"
|
|
||||||
<< "contrast INTEGER DEFAULT -1"
|
|
||||||
<< "gamma INTEGER DEFAULT -1";
|
|
||||||
|
|
||||||
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
|
|
||||||
returnValue = returnValue && successAddingColumns;
|
|
||||||
}
|
|
||||||
// TODO update hasBeenOpened value
|
|
||||||
|
|
||||||
if (pre7_1) {
|
|
||||||
{
|
|
||||||
QStringList columnDefs;
|
QStringList columnDefs;
|
||||||
columnDefs << "finished BOOLEAN DEFAULT 0"
|
columnDefs << "hasBeenOpened BOOLEAN DEFAULT 0"
|
||||||
<< "completed BOOLEAN DEFAULT 1";
|
<< "rating INTEGER DEFAULT 0"
|
||||||
bool successAddingColumns = addColumns("folder", columnDefs, db);
|
<< "currentPage INTEGER DEFAULT 1"
|
||||||
returnValue = returnValue && successAddingColumns;
|
<< "bookmark1 INTEGER DEFAULT -1"
|
||||||
}
|
<< "bookmark2 INTEGER DEFAULT -1"
|
||||||
|
<< "bookmark3 INTEGER DEFAULT -1"
|
||||||
|
<< "brightness INTEGER DEFAULT -1"
|
||||||
|
<< "contrast INTEGER DEFAULT -1"
|
||||||
|
<< "gamma INTEGER DEFAULT -1";
|
||||||
|
|
||||||
{ // comic_info
|
|
||||||
QStringList columnDefs;
|
|
||||||
columnDefs << "comicVineID TEXT DEFAULT NULL";
|
|
||||||
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
|
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
|
||||||
returnValue = returnValue && successAddingColumns;
|
returnValue = returnValue && successAddingColumns;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (pre8) {
|
if (pre7_1) {
|
||||||
bool successCreatingNewTables = createV8Tables(db);
|
{
|
||||||
returnValue = returnValue && successCreatingNewTables;
|
QStringList columnDefs;
|
||||||
}
|
columnDefs << "finished BOOLEAN DEFAULT 0"
|
||||||
|
<< "completed BOOLEAN DEFAULT 1";
|
||||||
if (pre9_5) {
|
bool successAddingColumns = addColumns("folder", columnDefs, db);
|
||||||
{ // folder
|
returnValue = returnValue && successAddingColumns;
|
||||||
QStringList columnDefs;
|
|
||||||
// a full library update is needed after updating the table
|
|
||||||
columnDefs << "numChildren INTEGER";
|
|
||||||
columnDefs << "firstChildHash TEXT";
|
|
||||||
columnDefs << "customImage TEXT";
|
|
||||||
bool successAddingColumns = addColumns("folder", columnDefs, db);
|
|
||||||
returnValue = returnValue && successAddingColumns;
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // comic_info
|
|
||||||
QStringList columnDefs;
|
|
||||||
columnDefs << "lastTimeOpened INTEGER";
|
|
||||||
columnDefs << "coverSizeRatio REAL";
|
|
||||||
columnDefs << "originalCoverSize TEXT";
|
|
||||||
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
|
|
||||||
returnValue = returnValue && successAddingColumns;
|
|
||||||
|
|
||||||
QSqlQuery queryIndexLastTimeOpened(db);
|
|
||||||
bool successCreatingIndex = queryIndexLastTimeOpened.exec("CREATE INDEX last_time_opened_index ON comic_info (lastTimeOpened)");
|
|
||||||
returnValue = returnValue && successCreatingIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update folders info
|
|
||||||
{
|
|
||||||
DBHelper::updateChildrenInfo(db);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
QSqlQuery selectQuery(db);
|
|
||||||
selectQuery.prepare("SELECT id, hash FROM comic_info");
|
|
||||||
selectQuery.exec();
|
|
||||||
|
|
||||||
db.transaction();
|
|
||||||
|
|
||||||
QSqlQuery updateCoverInfo(db);
|
|
||||||
updateCoverInfo.prepare("UPDATE comic_info SET coverSizeRatio = :coverSizeRatio WHERE id = :id");
|
|
||||||
|
|
||||||
QImageReader thumbnail;
|
|
||||||
while (selectQuery.next()) {
|
|
||||||
auto coverPath = LibraryPaths::coverPath(libraryPath, selectQuery.value(1).toString());
|
|
||||||
thumbnail.setFileName(coverPath);
|
|
||||||
|
|
||||||
float coverSizeRatio = static_cast<float>(thumbnail.size().width()) / thumbnail.size().height();
|
|
||||||
updateCoverInfo.bindValue(":coverSizeRatio", coverSizeRatio);
|
|
||||||
updateCoverInfo.bindValue(":id", selectQuery.value(0));
|
|
||||||
|
|
||||||
updateCoverInfo.exec();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db.commit();
|
{ // comic_info
|
||||||
|
QStringList columnDefs;
|
||||||
|
columnDefs << "comicVineID TEXT DEFAULT NULL";
|
||||||
|
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
|
||||||
|
returnValue = returnValue && successAddingColumns;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (pre9_8) {
|
if (pre8) {
|
||||||
{ // comic_info
|
bool successCreatingNewTables = createV8Tables(db);
|
||||||
QStringList columnDefs;
|
returnValue = returnValue && successCreatingNewTables;
|
||||||
columnDefs << "manga BOOLEAN DEFAULT 0";
|
|
||||||
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
|
|
||||||
returnValue = returnValue && successAddingColumns;
|
|
||||||
}
|
}
|
||||||
{ // folder
|
|
||||||
QStringList columnDefs;
|
|
||||||
columnDefs << "manga BOOLEAN DEFAULT 0";
|
|
||||||
bool successAddingColumns = addColumns("folder", columnDefs, db);
|
|
||||||
returnValue = returnValue && successAddingColumns;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pre9_13) {
|
if (pre9_5) {
|
||||||
{ // comic_info
|
{ // folder
|
||||||
QStringList columnDefs;
|
QStringList columnDefs;
|
||||||
columnDefs << "added INTEGER";
|
// a full library update is needed after updating the table
|
||||||
columnDefs << "type INTEGER DEFAULT 0"; // 0 = comic, 1 = manga, 2 = manga left to right, 3 = webcomic,
|
columnDefs << "numChildren INTEGER";
|
||||||
columnDefs << "editor TEXT";
|
columnDefs << "firstChildHash TEXT";
|
||||||
columnDefs << "imprint TEXT";
|
columnDefs << "customImage TEXT";
|
||||||
columnDefs << "teams TEXT";
|
bool successAddingColumns = addColumns("folder", columnDefs, db);
|
||||||
columnDefs << "locations TEXT";
|
returnValue = returnValue && successAddingColumns;
|
||||||
columnDefs << "series TEXT";
|
}
|
||||||
columnDefs << "alternateSeries TEXT";
|
|
||||||
columnDefs << "alternateNumber TEXT";
|
|
||||||
columnDefs << "alternateCount INTEGER";
|
|
||||||
columnDefs << "languageISO TEXT";
|
|
||||||
columnDefs << "seriesGroup TEXT";
|
|
||||||
columnDefs << "mainCharacterOrTeam TEXT";
|
|
||||||
columnDefs << "review TEXT";
|
|
||||||
columnDefs << "tags TEXT";
|
|
||||||
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
|
|
||||||
returnValue = returnValue && successAddingColumns;
|
|
||||||
|
|
||||||
QSqlQuery updateTypeQueryToManga(db);
|
{ // comic_info
|
||||||
updateTypeQueryToManga.prepare("UPDATE comic_info SET type = manga");
|
QStringList columnDefs;
|
||||||
bool successMigratingManga = updateTypeQueryToManga.exec();
|
columnDefs << "lastTimeOpened INTEGER";
|
||||||
returnValue = returnValue && successMigratingManga;
|
columnDefs << "coverSizeRatio REAL";
|
||||||
|
columnDefs << "originalCoverSize TEXT";
|
||||||
|
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
|
||||||
|
returnValue = returnValue && successAddingColumns;
|
||||||
|
|
||||||
QSqlQuery updateNumberQueryToBis(db);
|
QSqlQuery queryIndexLastTimeOpened(db);
|
||||||
updateNumberQueryToBis.prepare("UPDATE comic_info SET number = number + 0.5 WHERE isBis = 1");
|
bool successCreatingIndex = queryIndexLastTimeOpened.exec("CREATE INDEX last_time_opened_index ON comic_info (lastTimeOpened)");
|
||||||
bool successMigratingBis = updateNumberQueryToBis.exec();
|
returnValue = returnValue && successCreatingIndex;
|
||||||
returnValue = returnValue && successMigratingBis;
|
}
|
||||||
}
|
|
||||||
{ // folder
|
|
||||||
QStringList columnDefs;
|
|
||||||
columnDefs << "added INTEGER";
|
|
||||||
columnDefs << "updated INTEGER";
|
|
||||||
columnDefs << "type INTEGER DEFAULT 0";
|
|
||||||
|
|
||||||
bool successAddingColumns = addColumns("folder", columnDefs, db);
|
// update folders info
|
||||||
returnValue = returnValue && successAddingColumns;
|
{
|
||||||
|
DBHelper::updateChildrenInfo(db);
|
||||||
|
}
|
||||||
|
|
||||||
QSqlQuery updateTypeQueryToManga(db);
|
{
|
||||||
updateTypeQueryToManga.prepare("UPDATE folder SET type = manga");
|
QSqlQuery selectQuery(db);
|
||||||
bool successMigratingManga = updateTypeQueryToManga.exec();
|
selectQuery.prepare("SELECT id, hash FROM comic_info");
|
||||||
returnValue = returnValue && successMigratingManga;
|
selectQuery.exec();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure that INTEGER types migrated to TEXT are actually changed in the table definition to avoid internal type castings, this happened in 9.13 but a migration wasn't shipped with that version.
|
db.transaction();
|
||||||
if (pre9_14) {
|
|
||||||
{
|
|
||||||
bool pre9_14_successfulMigration = true;
|
|
||||||
|
|
||||||
QSqlQuery pragmaFKOFF(db);
|
QSqlQuery updateCoverInfo(db);
|
||||||
pragmaFKOFF.prepare("PRAGMA foreign_keys=OFF");
|
updateCoverInfo.prepare("UPDATE comic_info SET coverSizeRatio = :coverSizeRatio WHERE id = :id");
|
||||||
pre9_14_successfulMigration = pre9_14_successfulMigration && pragmaFKOFF.exec();
|
|
||||||
|
|
||||||
db.transaction();
|
QImageReader thumbnail;
|
||||||
|
while (selectQuery.next()) {
|
||||||
|
auto coverPath = LibraryPaths::coverPath(libraryPath, selectQuery.value(1).toString());
|
||||||
|
thumbnail.setFileName(coverPath);
|
||||||
|
|
||||||
pre9_14_successfulMigration = pre9_14_successfulMigration && createComicInfoTable(db, "comic_info_migration");
|
float coverSizeRatio = static_cast<float>(thumbnail.size().width()) / thumbnail.size().height();
|
||||||
|
updateCoverInfo.bindValue(":coverSizeRatio", coverSizeRatio);
|
||||||
|
updateCoverInfo.bindValue(":id", selectQuery.value(0));
|
||||||
|
|
||||||
QSqlQuery copyComicInfoToComicInfoMigration(db);
|
updateCoverInfo.exec();
|
||||||
copyComicInfoToComicInfoMigration.prepare("INSERT INTO comic_info_migration SELECT * FROM comic_info");
|
}
|
||||||
pre9_14_successfulMigration = pre9_14_successfulMigration && copyComicInfoToComicInfoMigration.exec();
|
|
||||||
|
|
||||||
QSqlQuery dropComicInfo(db);
|
|
||||||
dropComicInfo.prepare("DROP TABLE comic_info");
|
|
||||||
pre9_14_successfulMigration = pre9_14_successfulMigration && dropComicInfo.exec();
|
|
||||||
|
|
||||||
QSqlQuery renameComicInfoMigrationToComicInfo(db);
|
|
||||||
renameComicInfoMigrationToComicInfo.prepare("ALTER TABLE comic_info_migration RENAME TO comic_info");
|
|
||||||
pre9_14_successfulMigration = pre9_14_successfulMigration && renameComicInfoMigrationToComicInfo.exec();
|
|
||||||
|
|
||||||
if (pre9_14_successfulMigration)
|
|
||||||
db.commit();
|
db.commit();
|
||||||
else
|
}
|
||||||
db.rollback();
|
|
||||||
|
|
||||||
QSqlQuery pragmaFKON1("PRAGMA foreign_keys=ON", db);
|
|
||||||
|
|
||||||
returnValue = returnValue && pre9_14_successfulMigration;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (pre9_16) {
|
if (pre9_8) {
|
||||||
{ // comic_info
|
{ // comic_info
|
||||||
QStringList columnDefs;
|
QStringList columnDefs;
|
||||||
columnDefs << "imageFiltersJson TEXT";
|
columnDefs << "manga BOOLEAN DEFAULT 0";
|
||||||
columnDefs << "lastTimeImageFiltersSet INTEGER DEFAULT 0";
|
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
|
||||||
|
returnValue = returnValue && successAddingColumns;
|
||||||
|
}
|
||||||
|
{ // folder
|
||||||
|
QStringList columnDefs;
|
||||||
|
columnDefs << "manga BOOLEAN DEFAULT 0";
|
||||||
|
bool successAddingColumns = addColumns("folder", columnDefs, db);
|
||||||
|
returnValue = returnValue && successAddingColumns;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
columnDefs << "lastTimeCoverSet INTEGER DEFAULT 0";
|
if (pre9_13) {
|
||||||
columnDefs << "usesExternalCover BOOLEAN DEFAULT 0";
|
{ // comic_info
|
||||||
|
QStringList columnDefs;
|
||||||
|
columnDefs << "added INTEGER";
|
||||||
|
columnDefs << "type INTEGER DEFAULT 0"; // 0 = comic, 1 = manga, 2 = manga left to right, 3 = webcomic,
|
||||||
|
columnDefs << "editor TEXT";
|
||||||
|
columnDefs << "imprint TEXT";
|
||||||
|
columnDefs << "teams TEXT";
|
||||||
|
columnDefs << "locations TEXT";
|
||||||
|
columnDefs << "series TEXT";
|
||||||
|
columnDefs << "alternateSeries TEXT";
|
||||||
|
columnDefs << "alternateNumber TEXT";
|
||||||
|
columnDefs << "alternateCount INTEGER";
|
||||||
|
columnDefs << "languageISO TEXT";
|
||||||
|
columnDefs << "seriesGroup TEXT";
|
||||||
|
columnDefs << "mainCharacterOrTeam TEXT";
|
||||||
|
columnDefs << "review TEXT";
|
||||||
|
columnDefs << "tags TEXT";
|
||||||
|
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
|
||||||
|
returnValue = returnValue && successAddingColumns;
|
||||||
|
|
||||||
columnDefs << "lastTimeMetadataSet INTEGER DEFAULT 0";
|
QSqlQuery updateTypeQueryToManga(db);
|
||||||
|
updateTypeQueryToManga.prepare("UPDATE comic_info SET type = manga");
|
||||||
|
bool successMigratingManga = updateTypeQueryToManga.exec();
|
||||||
|
returnValue = returnValue && successMigratingManga;
|
||||||
|
|
||||||
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
|
QSqlQuery updateNumberQueryToBis(db);
|
||||||
returnValue = returnValue && successAddingColumns;
|
updateNumberQueryToBis.prepare("UPDATE comic_info SET number = number + 0.5 WHERE isBis = 1");
|
||||||
|
bool successMigratingBis = updateNumberQueryToBis.exec();
|
||||||
|
returnValue = returnValue && successMigratingBis;
|
||||||
|
}
|
||||||
|
{ // folder
|
||||||
|
QStringList columnDefs;
|
||||||
|
columnDefs << "added INTEGER";
|
||||||
|
columnDefs << "updated INTEGER";
|
||||||
|
columnDefs << "type INTEGER DEFAULT 0";
|
||||||
|
|
||||||
|
bool successAddingColumns = addColumns("folder", columnDefs, db);
|
||||||
|
returnValue = returnValue && successAddingColumns;
|
||||||
|
|
||||||
|
QSqlQuery updateTypeQueryToManga(db);
|
||||||
|
updateTypeQueryToManga.prepare("UPDATE folder SET type = manga");
|
||||||
|
bool successMigratingManga = updateTypeQueryToManga.exec();
|
||||||
|
returnValue = returnValue && successMigratingManga;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure that INTEGER types migrated to TEXT are actually changed in the table definition to avoid internal type castings, this happened in 9.13 but a migration wasn't shipped with that version.
|
||||||
|
if (pre9_14) {
|
||||||
|
{
|
||||||
|
bool pre9_14_successfulMigration = true;
|
||||||
|
|
||||||
|
QSqlQuery pragmaFKOFF(db);
|
||||||
|
pragmaFKOFF.prepare("PRAGMA foreign_keys=OFF");
|
||||||
|
pre9_14_successfulMigration = pre9_14_successfulMigration && pragmaFKOFF.exec();
|
||||||
|
|
||||||
|
pre9_14_successfulMigration = pre9_14_successfulMigration && createComicInfoTable(db, "comic_info_migration");
|
||||||
|
|
||||||
|
QSqlQuery copyComicInfoToComicInfoMigration(db);
|
||||||
|
copyComicInfoToComicInfoMigration.prepare("INSERT INTO comic_info_migration SELECT * FROM comic_info");
|
||||||
|
pre9_14_successfulMigration = pre9_14_successfulMigration && copyComicInfoToComicInfoMigration.exec();
|
||||||
|
|
||||||
|
QSqlQuery dropComicInfo(db);
|
||||||
|
dropComicInfo.prepare("DROP TABLE comic_info");
|
||||||
|
pre9_14_successfulMigration = pre9_14_successfulMigration && dropComicInfo.exec();
|
||||||
|
|
||||||
|
QSqlQuery renameComicInfoMigrationToComicInfo(db);
|
||||||
|
renameComicInfoMigrationToComicInfo.prepare("ALTER TABLE comic_info_migration RENAME TO comic_info");
|
||||||
|
pre9_14_successfulMigration = pre9_14_successfulMigration && renameComicInfoMigrationToComicInfo.exec();
|
||||||
|
|
||||||
|
QSqlQuery pragmaFKON1("PRAGMA foreign_keys=ON", db);
|
||||||
|
|
||||||
|
returnValue = returnValue && pre9_14_successfulMigration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pre9_16) {
|
||||||
|
{ // comic_info
|
||||||
|
QStringList columnDefs;
|
||||||
|
columnDefs << "imageFiltersJson TEXT";
|
||||||
|
columnDefs << "lastTimeImageFiltersSet INTEGER DEFAULT 0";
|
||||||
|
|
||||||
|
columnDefs << "lastTimeCoverSet INTEGER DEFAULT 0";
|
||||||
|
columnDefs << "usesExternalCover BOOLEAN DEFAULT 0";
|
||||||
|
|
||||||
|
columnDefs << "lastTimeMetadataSet INTEGER DEFAULT 0";
|
||||||
|
|
||||||
|
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
|
||||||
|
returnValue = returnValue && successAddingColumns;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnValue) {
|
||||||
|
QSqlQuery updateVersion(db);
|
||||||
|
updateVersion.prepare("UPDATE db_info SET "
|
||||||
|
"version = :version");
|
||||||
|
updateVersion.bindValue(":version", DB_VERSION);
|
||||||
|
updateVersion.exec();
|
||||||
|
|
||||||
|
returnValue = updateVersion.numRowsAffected() > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (returnValue) {
|
if (returnValue) {
|
||||||
QSqlQuery updateVersion(db);
|
if (!db.commit()) {
|
||||||
updateVersion.prepare("UPDATE db_info SET "
|
QLOG_ERROR() << "Failed to commit transaction for database update";
|
||||||
"version = :version");
|
returnValue = false;
|
||||||
updateVersion.bindValue(":version", DB_VERSION);
|
}
|
||||||
updateVersion.exec();
|
} else {
|
||||||
|
db.rollback();
|
||||||
returnValue = updateVersion.numRowsAffected() > 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
connectionName = db.connectionName();
|
connectionName = db.connectionName();
|
||||||
|
|||||||
Reference in New Issue
Block a user