File indexing completed on 2025-03-16 13:27:30
0001 /* 0002 SPDX-FileCopyrightText: 2023-2024 Laurent Montel <montel.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "localdatabasebase.h" 0008 #include "localdatabaseutils.h" 0009 #include "ruqola_database_debug.h" 0010 0011 #include <QDir> 0012 #include <QFileInfo> 0013 #include <QSqlDatabase> 0014 #include <QSqlError> 0015 #include <QSqlQuery> 0016 0017 LocalDatabaseBase::LocalDatabaseBase(const QString &basePath, LocalDatabaseBase::DatabaseType type) 0018 : mBasePath(basePath) 0019 , mDatabaseType(type) 0020 { 0021 } 0022 0023 LocalDatabaseBase::~LocalDatabaseBase() = default; 0024 0025 QString LocalDatabaseBase::dbFileName(const QString &accountName, const QString &roomName) const 0026 { 0027 const QString dirPath = mBasePath + accountName; 0028 return dirPath + QLatin1Char('/') + roomName + QStringLiteral(".sqlite"); 0029 } 0030 0031 QString LocalDatabaseBase::dbFileName(const QString &accountName) const 0032 { 0033 const QString dirPath = mBasePath + accountName; 0034 return dirPath + QLatin1Char('/') + accountName + QStringLiteral(".sqlite"); 0035 } 0036 0037 QString LocalDatabaseBase::schemaDatabaseStr() const 0038 { 0039 return schemaDataBase(); 0040 } 0041 0042 QString LocalDatabaseBase::schemaDataBase() const 0043 { 0044 Q_ASSERT(false); 0045 return {}; 0046 } 0047 0048 QString LocalDatabaseBase::databaseName(const QString &name) const 0049 { 0050 QString prefix; 0051 switch (mDatabaseType) { 0052 case DatabaseType::Unknown: 0053 qCWarning(RUQOLA_DATABASE_LOG) << "Unknown data base it's a bug"; 0054 break; 0055 case DatabaseType::Account: 0056 prefix = QStringLiteral("accounts-"); 0057 break; 0058 case DatabaseType::Rooms: 0059 prefix = QStringLiteral("rooms-"); 0060 break; 0061 case DatabaseType::Message: 0062 prefix = QStringLiteral("messages-"); 0063 break; 0064 case DatabaseType::Global: 0065 prefix = QStringLiteral("global-"); 0066 break; 0067 case DatabaseType::Logger: 0068 break; 0069 } 0070 return prefix + name; 0071 } 0072 0073 bool LocalDatabaseBase::checkDataBase(const QString &accountName, const QString &_roomName, QSqlDatabase &db) 0074 { 0075 const QString roomName = LocalDatabaseUtils::fixRoomName(_roomName); 0076 const QString dbName = databaseName(accountName + QLatin1Char('-') + roomName); 0077 db = QSqlDatabase::database(dbName); 0078 if (!db.isValid()) { 0079 qCWarning(RUQOLA_DATABASE_LOG) << "The assumption was wrong, deleteMessage was called before addMessage, in account" << accountName << "room" 0080 << roomName << "database file " << dbName; 0081 return false; 0082 } 0083 Q_ASSERT(db.isOpen()); 0084 return true; 0085 } 0086 0087 bool LocalDatabaseBase::checkDataBase(const QString &accountName, QSqlDatabase &db) 0088 { 0089 const QString dbName = databaseName(accountName); 0090 db = QSqlDatabase::database(dbName); 0091 if (!db.isValid()) { 0092 qCWarning(RUQOLA_DATABASE_LOG) << "The assumption was wrong, deleteMessage was called before addMessage, in account" << accountName << "database file " 0093 << dbName; 0094 return false; 0095 } 0096 Q_ASSERT(db.isValid()); 0097 Q_ASSERT(db.isOpen()); 0098 return true; 0099 } 0100 0101 bool LocalDatabaseBase::initializeDataBase(const QString &accountName, const QString &_roomName, QSqlDatabase &db) 0102 { 0103 const QString roomName = LocalDatabaseUtils::fixRoomName(_roomName); 0104 const QString dbName = databaseName(accountName + QLatin1Char('-') + roomName); 0105 db = QSqlDatabase::database(dbName); 0106 if (!db.isValid()) { 0107 db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), dbName); 0108 const QString dirPath = mBasePath + accountName; 0109 if (!QDir().mkpath(dirPath)) { 0110 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't create" << dirPath; 0111 return false; 0112 } 0113 const QString fileName = dbFileName(accountName, roomName); 0114 const bool newDb = QFileInfo::exists(fileName); 0115 db.setDatabaseName(fileName); 0116 if (!db.open()) { 0117 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't create" << db.databaseName(); 0118 return false; 0119 } 0120 if (!newDb) { 0121 db.exec(schemaDataBase()); 0122 if (db.lastError().isValid()) { 0123 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't create table LOGS in" << db.databaseName() << ":" << db.lastError(); 0124 return false; 0125 } 0126 } 0127 // Using the write-ahead log and sync = NORMAL for faster writes 0128 // (idea taken from kactivities-stat) 0129 db.exec(QStringLiteral("PRAGMA synchronous = 1")); 0130 // use the write-ahead log (requires sqlite > 3.7.0) 0131 db.exec(QStringLiteral("PRAGMA journal_mode = WAL")); 0132 } 0133 0134 Q_ASSERT(db.isValid()); 0135 Q_ASSERT(db.isOpen()); 0136 return true; 0137 } 0138 0139 bool LocalDatabaseBase::initializeDataBase(const QString &accountName, QSqlDatabase &db) 0140 { 0141 const QString dbName = databaseName(accountName); 0142 db = QSqlDatabase::database(dbName); 0143 if (!db.isValid()) { 0144 db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), dbName); 0145 const QString dirPath = mBasePath + accountName; 0146 if (!QDir().mkpath(dirPath)) { 0147 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't create" << dirPath; 0148 return false; 0149 } 0150 const QString fileName = dbFileName(accountName); 0151 const bool newDb = QFileInfo::exists(fileName); 0152 db.setDatabaseName(fileName); 0153 if (!db.open()) { 0154 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't create" << db.databaseName(); 0155 return false; 0156 } 0157 if (!newDb) { 0158 db.exec(schemaDataBase()); 0159 if (db.lastError().isValid()) { 0160 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't create table LOGS in" << db.databaseName() << ":" << db.lastError(); 0161 return false; 0162 } 0163 } 0164 // Using the write-ahead log and sync = NORMAL for faster writes 0165 // (idea taken from kactivities-stat) 0166 db.exec(QStringLiteral("PRAGMA synchronous = 1")); 0167 // use the write-ahead log (requires sqlite > 3.7.0) 0168 db.exec(QStringLiteral("PRAGMA journal_mode = WAL")); 0169 } 0170 0171 Q_ASSERT(db.isValid()); 0172 Q_ASSERT(db.isOpen()); 0173 return true; 0174 }