1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-07-03 23:50:33 +02:00
Files
joplin/QtClient/JoplinQtClient/database.cpp
2017-02-09 20:14:36 +00:00

271 lines
6.8 KiB
C++
Executable File

#include "database.h"
using namespace jop;
Database::Database() : db_(NULL), isClosed_(true) {}
Database::~Database() {
if (!isClosed()) qWarning() << "Database::close() should be called explicitely";
}
void Database::initialize(const QString &path) {
version_ = -1;
transactionCount_ = 0;
logQueries_ = true;
// QFile::remove(path);
db_ = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE"));
db_->setDatabaseName(path);
if (!db_->open()) {
qFatal("Error: connection with database fail");
} else {
qInfo() << "Database: connection ok";
isClosed_ = false;
}
upgrade();
}
// See https://bugreports.qt.io/browse/QTBUG-35977 for the reason why it's necessary
// to manually destroy the QSqlDatabase instance (i.e. it cannot be done in the
// Database::~Database).
void Database::close() {
if (db_ && db_->open()) db_->close();
delete db_;
db_ = NULL;
isClosed_ = true;
}
bool Database::isClosed() const {
return isClosed_;
}
QSqlDatabase* Database::database() const {
if (isClosed_) qFatal("Database::database: Database is closed");
return db_;
}
QSqlQuery Database::buildSqlQuery(Database::QueryType type, const QString &tableName, const QStringList &fields, const VariantVector &values, const QString &whereCondition) {
QString sql;
if (type == Insert) {
QString fieldString = "";
QString valueString = "";
for (int i = 0; i < fields.length(); i++) {
QString f = fields[i];
if (fieldString != "") fieldString += ", ";
if (valueString != "") valueString += ", ";
fieldString += QString("`%1`").arg(f);
valueString += ":" + f;
}
sql = QString("INSERT INTO `%1` (%2) VALUES (%3)").arg(tableName).arg(fieldString).arg(valueString);
} else if (type == Update) {
QString fieldString = "";
for (int i = 0; i < fields.length(); i++) {
QString f = fields[i];
if (fieldString != "") fieldString += ", ";
fieldString += QString("`%1`=:%1").arg(f);
}
sql = QString("UPDATE `%1` SET %2").arg(tableName).arg(fieldString);
if (whereCondition != "") sql += " WHERE " + whereCondition;
}
QSqlQuery query(*db_);
bool ok = query.prepare(sql);
if (!ok) {
printError(query);
return query;
}
for (int i = 0; i < values.size(); i++) {
QVariant v = values[i];
QString fieldName = ":" + fields[i];
if (v.type() == QVariant::String) {
query.bindValue(fieldName, v.toString());
} else if (v.type() == QVariant::Int) {
query.bindValue(fieldName, v.toInt());
} else if (v.isNull()) {
query.bindValue(fieldName, (int)NULL);
} else if (v.type() == QVariant::Double) {
query.bindValue(fieldName, v.toDouble());
} else if (v.type() == (QVariant::Type)QMetaType::Float) {
query.bindValue(fieldName, v.toFloat());
} else if (v.type() == QVariant::LongLong) {
query.bindValue(fieldName, v.toLongLong());
} else if (v.type() == QVariant::UInt) {
query.bindValue(fieldName, v.toUInt());
} else if (v.type() == QVariant::Char) {
query.bindValue(fieldName, v.toChar());
} else {
qWarning() << Q_FUNC_INFO << "Unsupported variant type:" << v.type();
}
}
return query;
}
QSqlQuery Database::buildSqlQuery(Database::QueryType type, const QString &tableName, const QMap<QString, QVariant> &values, const QString &whereCondition) {
QStringList fields;
VariantVector fieldValues;
for (QMap<QString, QVariant>::const_iterator it = values.begin(); it != values.end(); ++it) {
fields.push_back(it.key());
fieldValues.push_back(it.value());
}
return buildSqlQuery(type, tableName, fields, fieldValues, whereCondition);
}
void Database::printError(const QSqlQuery& query) const {
if (query.lastError().isValid()) {
qCritical().noquote() << "SQL error: " << query.lastError().text().trimmed() << ". Query was: " << query.lastQuery();
QMapIterator<QString, QVariant> i(query.boundValues());
while (i.hasNext()) {
i.next();
qCritical() << i.key() << "=" << i.value().toString();
}
}
}
bool Database::errorCheck(const QSqlQuery& query) {
if (query.lastError().isValid()) {
printError(query);
return false;
}
return true;
}
bool Database::transaction() {
transactionCount_++;
if (transactionCount_ > 1) return true;
return db_->transaction();
}
bool Database::commit() {
transactionCount_--;
if (transactionCount_ < 0) {
transactionCount_ = 0;
qCritical() << "Attempting commit on a database that is not in transaction mode";
return false;
}
if (transactionCount_ <= 0) {
return db_->commit();
}
return true;
}
bool Database::execQuery(QSqlQuery &query) {
if (logQueries_) {
QString sql = query.lastQuery();
qDebug().noquote() << "SQL:" << sql;
QMapIterator<QString, QVariant> i(query.boundValues());
while (i.hasNext()) {
i.next();
qDebug().noquote() << "SQL:" << i.key() << "=" << i.value().toString();
}
}
return query.exec();
}
bool Database::execQuery(const QString &sql) {
QSqlQuery query(sql, *db_);
return execQuery(query);
}
QSqlQuery Database::prepare(const QString &sql) {
QSqlQuery query(*db_);
query.prepare(sql);
return query;
}
int Database::version() const {
if (version_ >= 0) return version_;
QSqlQuery query = db_->exec("SELECT * FROM version");
bool result = query.next();
if (!result) return 0;
QSqlRecord r = query.record();
int i_version = r.indexOf("version");
version_ = query.value(i_version).toInt();
return version_;
}
QStringList Database::sqlStringToLines(const QString& sql) {
QStringList statements;
QStringList lines = sql.split("\n");
QString statement;
foreach (QString line, lines) {
line = line.trimmed();
if (line == "") continue;
if (line.left(2) == "--") continue;
statement += line;
if (line[line.length() - 1] == ';') {
statements.append(statement);
statement = "";
}
}
return statements;
}
void Database::upgrade() {
// INSTRUCTIONS TO UPGRADE THE DATABASE:
//
// 1. Add the new version number to the existingDatabaseVersions array
// 2. Add the upgrade logic to the "switch (targetVersion)" statement below
QList<int> existingVersions;
existingVersions << 1;
int versionIndex = existingVersions.indexOf(version());
if (versionIndex == existingVersions.length() - 1) return;
while (versionIndex < existingVersions.length() - 1) {
int targetVersion = existingVersions[versionIndex + 1];
qDebug() << "Upgrading database to version " << targetVersion;
db_->transaction();
switch (targetVersion) {
case 1:
QFile f(":/schema.sql");
if (!f.open(QFile::ReadOnly | QFile::Text)) {
qFatal("Cannot open database schema file");
return;
}
QTextStream in(&f);
QString schemaSql = in.readAll();
QStringList lines = sqlStringToLines(schemaSql);
foreach (const QString& line, lines) {
db_->exec(line);
}
break;
}
db_->exec(QString("UPDATE version SET version = %1").arg(targetVersion));
db_->commit();
versionIndex++;
}
}
Database databaseInstance_;
Database& jop::db() {
return databaseInstance_;
}