xca/lib/sql.cpp
Christian Hohnstaedt 993da2d474 Use C++11 initializers for all non-static class members
When XCA started in 2002, there were no C++ initializers.
Drop explicit initializers from the constructors.

 - Fix indentations of section declarators.
 - Replace NULL by nullptr when feasible.
 - Sort private section: properties first, then methods.
2023-10-08 22:19:18 +02:00

224 lines
4.7 KiB
C++

/* vi: set sw=4 ts=4:
*
* Copyright (C) 2017 Christian Hohnstaedt.
*
* All rights reserved.
*/
#include <QString>
#include <QRegularExpression>
#include <QDebug>
#include "base.h"
#include "sql.h"
#include "settings.h"
#include "XcaWarningCore.h"
int DbTransaction::mutex;
int DbTransaction::error;
bool DbTransaction::hasTransaction;
QList<quint64> DbTransaction::items;
quint64 DbTransaction::DatabaseStamp;
void DbTransaction::debug(const char *func, const char *file, int line)
{
qDebug() << QString("%1(%2) Transaction: %3 Level %4, E:%5 ")
.arg(file + QString(file).lastIndexOf("/") +1)
.arg(line).arg(func).arg(mutex).arg(error);
}
DbTransaction::~DbTransaction()
{
if (has_begun)
rollback("Destructor", 0);
}
bool DbTransaction::begin(const char *file, int line)
{
mutex++;
has_begun = true;
debug("Begin", file, line);
if (mutex > 1 || !hasTransaction)
return true;
QSqlDatabase db = QSqlDatabase::database();
bool ret = db.transaction();
if (!ret)
XCA_SQLERROR(db.lastError());
return ret;
}
bool DbTransaction::finish(const char *oper, const char *file, int line)
{
if (!has_begun)
return true;
if (mutex > 0)
mutex--;
else
qCritical() << "Unbalanced DB Transaction in " << oper;
debug(oper, file, line);
has_begun = false;
if (mutex > 0)
return true;
QSqlDatabase db = QSqlDatabase::database();
if (error) {
error = 0;
items.clear();
return hasTransaction ? db.rollback() : true;
}
mutex++;
XSqlQuery q;
SQL_PREPARE(q, "SELECT MAX(stamp) +1 from items");
q.exec();
if (q.first())
DatabaseStamp = q.value(0).toULongLong();
SQL_PREPARE(q, "UPDATE items SET stamp=? WHERE stamp=0");
q.bindValue(0, DatabaseStamp);
q.exec();
SQL_PREPARE(q, "UPDATE items SET stamp=? WHERE id=?");
q.bindValue(0, DatabaseStamp);
foreach(quint64 id, DbTransaction::items) {
q.bindValue(1, id);
q.exec();
}
mutex--;
items.clear();
bool ret = hasTransaction ? db.commit() : true;
if (!ret)
XCA_SQLERROR(db.lastError());
return ret;
}
bool DbTransaction::commit(const char *file, int line)
{
return finish("Commit", file, line);
}
bool DbTransaction::rollback(const char *file, int line)
{
error++;
return finish("Rollback", file, line);
}
bool DbTransaction::done(QSqlError e, const char *file, int line)
{
return e.isValid() ? rollback(file, line) : commit(file, line);
}
QString XSqlQuery::table_prefix;
int XSqlQuery::schemaVersion()
{
qDebug() << "table_prefix:" << table_prefix;;
return QSqlDatabase::database().tables()
.contains(table_prefix + "settings") ?
Settings["schema"] : 0;
}
QString XSqlQuery::rewriteQuery(QString _q)
{
static const QStringList tables {
"items" , "crls" , "private_keys" , "public_keys" ,
"tokens" , "token_mechanism" , "templates" , "certs" ,
"authority" , "revocations" , "requests" , "x509super" ,
"settings" ,
"view_public_keys" , "view_certs" , "view_requests" ,
"view_crls" , "view_templates" , "view_private",
};
lastq = query = _q;
if (table_prefix.isEmpty())
return query;
QString m = tables.join("|") + "|i_" + tables.join("|i_");
m = QString("\\b(%1)").arg(m);
query = query.replace(QRegularExpression(m), table_prefix + "\\1");
return query;
}
QString XSqlQuery::query_details()
{
QString lq = lastq;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
QVariantList list = boundValues();
#else
QVariantList list = boundValues().values();
#endif
QStringList sl;
if (query != lastq) {
lq = QString("%1 (PREFIX[%2]: %3)").arg(lastq)
.arg(table_prefix).arg(query);
}
for (int i = 0; i < list.size(); ++i)
sl << list.at(i).toString();
if (sl.size())
lq += QString("[%1]").arg(sl.join(", "));
return QString("%1:%2 (%3)").arg(file).arg(line).arg(lq);
}
QSqlError XSqlQuery::lastError()
{
QSqlError e = QSqlQuery::lastError();
if (!e.isValid())
return e;
return QSqlError(QString("%1 - %2").arg(e.driverText())
.arg(query_details()),
e.databaseText(), e.type(),
e.nativeErrorCode()
);
}
XSqlQuery::XSqlQuery() : QSqlQuery()
{
}
XSqlQuery::XSqlQuery(QString q) : QSqlQuery()
{
exec(q);
}
bool XSqlQuery::exec(QString q)
{
q = rewriteQuery(q);
file = ""; line = 0;
return QSqlQuery::exec(q);
}
bool XSqlQuery::exec()
{
QString res;
setForwardOnly(true);
bool r = QSqlQuery::exec();
if (isSelect()) {
res = QString("Rows selected: %1").arg(size());
} else {
res = QString("Rows affected: %1").arg(numRowsAffected());
if (!DbTransaction::active()) {
qCritical("########## MISSING Transaction in %s(%d)",
file, line);
}
}
qDebug() << QString("QUERY: %1 - %2").arg(query_details()).arg(res);
return r;
}
bool XSqlQuery::prepare(QString q)
{
q = rewriteQuery(q);
setForwardOnly(true);
return QSqlQuery::prepare(q);
}
void XSqlQuery::location(const char *f, int l)
{
file = f + QString(f).lastIndexOf("/") +1;
line = l;
}