618 lines
21 KiB
C++
618 lines
21 KiB
C++
/*
|
|
* Copyright (c) 2015, Technische Universität Kaiserslautern
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
|
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* Authors:
|
|
* Janik Schlemminger
|
|
* Robert Gernhardt
|
|
* Matthias Jung
|
|
* Derek Christ
|
|
*/
|
|
|
|
#include <QString>
|
|
#include <QFile>
|
|
#include <QStringList>
|
|
#include <QTextStream>
|
|
#include <QSqlError>
|
|
#include <iostream>
|
|
#include <QFileInfo>
|
|
#include <QDebug>
|
|
#include "data/tracedb.h"
|
|
#include "businessObjects/phases/phasefactory.h"
|
|
|
|
|
|
//define symbol printqueries if all queries should be printed to the console
|
|
//#define printqueries
|
|
|
|
using namespace std;
|
|
|
|
TraceDB::TraceDB(QString path, bool openExisting)
|
|
{
|
|
this->pathToDB = path;
|
|
|
|
database = QSqlDatabase::database(path);
|
|
if (database.isValid() && database.isOpen()) {
|
|
// Close the database connection if it exists and was not closed yet.
|
|
database.removeDatabase(path);
|
|
database.close();
|
|
}
|
|
|
|
database = QSqlDatabase::addDatabase("QSQLITE", path);
|
|
database.setDatabaseName(path);
|
|
database.open();
|
|
if (!openExisting)
|
|
dropAndCreateTables();
|
|
prepareQueries();
|
|
generalInfo = getGeneralInfoFromDB();
|
|
commandLengths = getCommandLengthsFromDB();
|
|
}
|
|
|
|
void TraceDB::prepareQueries()
|
|
{
|
|
selectTransactionsByTimespan = QSqlQuery(database);
|
|
selectTransactionsByTimespan.prepare(queryTexts.selectTransactionsByTimespan);
|
|
selectTransactionById = QSqlQuery(database);
|
|
|
|
selectTransactionById.prepare(queryTexts.selectTransactionById);
|
|
selectDebugMessagesByTimespan = QSqlQuery(database);
|
|
selectDebugMessagesByTimespan.prepare("SELECT time, Message FROM DebugMessages WHERE :begin <= time AND time <= :end ");
|
|
selectDebugMessagesByTimespanWithLimit = QSqlQuery(database);
|
|
selectDebugMessagesByTimespanWithLimit.prepare("SELECT time, Message FROM DebugMessages WHERE :begin <= time AND time <= :end LIMIT :limit");
|
|
|
|
checkDependenciesExist = QSqlQuery(database);
|
|
checkDependenciesExist.prepare(queryTexts.checkDependenciesExist);
|
|
selectDependenciesByTimespan = QSqlQuery(database);
|
|
selectDependenciesByTimespan.prepare(queryTexts.selectDependenciesByTimespan);
|
|
|
|
selectDependencyTypePercentages = QSqlQuery(database);
|
|
selectDependencyTypePercentages.prepare(queryTexts.selectDependencyTypePercentages);
|
|
selectTimeDependencyPercentages = QSqlQuery(database);
|
|
selectTimeDependencyPercentages.prepare(queryTexts.selectTimeDependencyPercentages);
|
|
selectDelayedPhasePercentages = QSqlQuery(database);
|
|
selectDelayedPhasePercentages.prepare(queryTexts.selectDelayedPhasePercentages);
|
|
selectDependencyPhasePercentages = QSqlQuery(database);
|
|
selectDependencyPhasePercentages.prepare(queryTexts.selectDependencyPhasePercentages);
|
|
}
|
|
|
|
void TraceDB::updateComments(const std::vector<CommentModel::Comment> &comments)
|
|
{
|
|
QSqlQuery query(database);
|
|
query.prepare("DELETE FROM Comments");
|
|
executeQuery(query);
|
|
query.prepare("insert into Comments values(:time,:text)");
|
|
|
|
for (const auto &comment : comments)
|
|
{
|
|
query.bindValue(":time", comment.time);
|
|
query.bindValue(":text", comment.text);
|
|
executeQuery(query);
|
|
}
|
|
}
|
|
|
|
void TraceDB::updateFileDescription(const QString &description)
|
|
{
|
|
QSqlQuery query(database);
|
|
query.prepare("UPDATE GeneralInfo SET Description=:description");
|
|
query.bindValue(":description", description);
|
|
executeQuery(query);
|
|
}
|
|
|
|
void TraceDB::refreshData()
|
|
{
|
|
generalInfo = getGeneralInfoFromDB();
|
|
}
|
|
|
|
//QueryText must select the fields
|
|
//TransactionID, Ranges.begin, Ranges.end, Address, TThread, TChannel, TBank, TRow, TColumn, Phases.ID AS PhaseID, PhaseName, PhaseBegin, PhaseEnd
|
|
vector<shared_ptr<Transaction>> TraceDB::getTransactionsWithCustomQuery(
|
|
QString queryText)
|
|
{
|
|
QSqlQuery query(database);
|
|
query.prepare(queryText);
|
|
executeQuery(query);
|
|
return parseTransactionsFromQuery(query);
|
|
}
|
|
|
|
vector<shared_ptr<Transaction>> TraceDB::getTransactionsInTimespan(const Timespan &span, bool updateVisiblePhases)
|
|
{
|
|
selectTransactionsByTimespan.bindValue(":begin", span.Begin());
|
|
selectTransactionsByTimespan.bindValue(":end", span.End());
|
|
executeQuery(selectTransactionsByTimespan);
|
|
return parseTransactionsFromQuery(selectTransactionsByTimespan, updateVisiblePhases);
|
|
}
|
|
|
|
void TraceDB::updateDependenciesInTimespan(const Timespan &span)
|
|
{
|
|
executeQuery(checkDependenciesExist);
|
|
if (checkDependenciesExist.next())
|
|
{
|
|
|
|
if (checkDependenciesExist.value(0).toInt() == 1)
|
|
{
|
|
selectDependenciesByTimespan.bindValue(":begin", span.Begin());
|
|
selectDependenciesByTimespan.bindValue(":end", span.End());
|
|
executeQuery(selectDependenciesByTimespan);
|
|
mUpdateDependenciesFromQuery(selectDependenciesByTimespan);
|
|
}
|
|
}
|
|
}
|
|
|
|
//TODO Remove exception
|
|
shared_ptr<Transaction> TraceDB::getTransactionByID(ID id)
|
|
{
|
|
selectTransactionById.bindValue(":id", id);
|
|
executeQuery(selectTransactionById);
|
|
auto result = parseTransactionsFromQuery(selectTransactionById);
|
|
if (!result.empty())
|
|
return result[0];
|
|
else
|
|
throw sqlException(("Transaction with ID " + QString::number(
|
|
id) + " not in DB").toStdString(), this->pathToDB.toStdString());
|
|
}
|
|
|
|
|
|
shared_ptr<Transaction> TraceDB::getNextActivate(traceTime time)
|
|
{
|
|
QSqlQuery query(database);
|
|
QString queryText = queryTexts.queryHead +
|
|
"WHERE PhaseBegin > :traceTime AND PhaseName "
|
|
"IN ('ACT','ACTB') ORDER BY PhaseBegin ASC LIMIT 1";
|
|
|
|
query.prepare(queryText);
|
|
query.bindValue(":traceTime", time);
|
|
executeQuery(query);
|
|
return parseTransactionFromQuery(query);
|
|
}
|
|
|
|
shared_ptr<Transaction> TraceDB::getNextPrecharge(traceTime time)
|
|
{
|
|
QSqlQuery query(database);
|
|
QString queryText = queryTexts.queryHead +
|
|
"WHERE PhaseBegin > :traceTime AND PhaseName "
|
|
"IN ('PRE','PREA','PREB','PRESB') ORDER BY PhaseBegin ASC LIMIT 1";
|
|
|
|
query.prepare(queryText);
|
|
query.bindValue(":traceTime", time);
|
|
executeQuery(query);
|
|
return parseTransactionFromQuery(query);
|
|
}
|
|
|
|
// shared_ptr<Transaction> TraceDB::getNextActb(ID currentTransactionId)
|
|
// {
|
|
// QSqlQuery query(database);
|
|
// QString queryText = queryTexts.queryHead +
|
|
// "WHERE TransactionID > :currentID AND PhaseName = 'ACTB' LIMIT 1";
|
|
//
|
|
// query.prepare(queryText);
|
|
// query.bindValue(":currentID", currentTransactionId);
|
|
// executeQuery(query);
|
|
// return parseTransactionFromQuery(query);
|
|
// }
|
|
|
|
// shared_ptr<Transaction> TraceDB::getNextPreb(ID currentTransactionId)
|
|
// {
|
|
// QSqlQuery query(database);
|
|
// QString queryText = queryTexts.queryHead +
|
|
// "WHERE TransactionID > :currentID AND PhaseName = 'PREB' LIMIT 1";
|
|
//
|
|
// query.prepare(queryText);
|
|
// query.bindValue(":currentID", currentTransactionId);
|
|
// executeQuery(query);
|
|
// return parseTransactionFromQuery(query);
|
|
// }
|
|
|
|
shared_ptr<Transaction> TraceDB::getNextRefresh(traceTime time)
|
|
{
|
|
QSqlQuery query(database);
|
|
QString queryText = queryTexts.queryHead +
|
|
"WHERE PhaseBegin > :traceTime AND PhaseName "
|
|
"IN ('REFA','REFB','REFSB','SREF','SREFB') ORDER BY PhaseBegin ASC LIMIT 1";
|
|
query.prepare(queryText);
|
|
query.bindValue(":traceTime", time);
|
|
executeQuery(query);
|
|
return parseTransactionFromQuery(query);
|
|
}
|
|
|
|
std::shared_ptr<Transaction> TraceDB::getNextCommand(traceTime time)
|
|
{
|
|
QSqlQuery query(database);
|
|
QString queryText = queryTexts.queryHead +
|
|
"WHERE PhaseBegin > :traceTime ORDER BY PhaseBegin ASC LIMIT 1";
|
|
query.prepare(queryText);
|
|
query.bindValue(":traceTime", time);
|
|
executeQuery(query);
|
|
return parseTransactionFromQuery(query);
|
|
}
|
|
|
|
// shared_ptr<Transaction> TraceDB::getNextRefb(ID currentTransactionId)
|
|
// {
|
|
// QSqlQuery query(database);
|
|
// QString queryText = queryTexts.queryHead +
|
|
// "WHERE TransactionID > :currentID AND PhaseName = 'REFB' LIMIT 1";
|
|
//
|
|
// query.prepare(queryText);
|
|
// query.bindValue(":currentID", currentTransactionId);
|
|
// executeQuery(query);
|
|
// return parseTransactionFromQuery(query);
|
|
// }
|
|
|
|
ID TraceDB::getTransactionIDFromPhaseID(ID phaseID)
|
|
{
|
|
QSqlQuery query(database);
|
|
query.prepare("SELECT Transact FROM Phases WHERE ID=:id");
|
|
query.bindValue(":id", phaseID);
|
|
executeQuery(query);
|
|
|
|
if (query.next()) {
|
|
return query.value(0).toInt();
|
|
} else {
|
|
throw sqlException("Phase with ID " + to_string(phaseID) + " not in db",
|
|
this->pathToDB.toStdString());
|
|
}
|
|
}
|
|
|
|
GeneralInfo *TraceDB::getGeneralInfoFromDB()
|
|
{
|
|
QSqlQuery query(database);
|
|
query.prepare("SELECT NumberOfTransactions, TraceEnd, NumberOfRanks, NumberOfBankgroups, NumberOfBanks, Clk, "
|
|
"UnitOfTime, Traces, Memspec, MCconfig, WindowSize, ControllerThread FROM GeneralInfo");
|
|
executeQuery(query);
|
|
|
|
if (query.next()) {
|
|
unsigned int numberOfTransactions = query.value(0).toInt();
|
|
traceTime traceEnd = query.value(1).toLongLong();
|
|
unsigned int numberOfRanks = query.value(2).toInt();
|
|
unsigned int numberOfBankgroups = query.value(3).toInt();
|
|
unsigned int numberOfBanks = query.value(4).toInt();
|
|
unsigned int clkPeriod = query.value(5).toInt();
|
|
QString unitOfTime = query.value(6).toString();
|
|
unsigned int numberOfPhases = getNumberOfPhases();
|
|
|
|
QString traces = "Traces: " + query.value(7).toString();
|
|
QString memspec = "Memspec: " + query.value(8).toString();
|
|
QString mcconfig = "MCconfig: " + query.value(9).toString();
|
|
unsigned int windowSize = query.value(10).toInt();
|
|
unsigned int controllerThread = query.value(11).toUInt();
|
|
|
|
return new GeneralInfo(numberOfTransactions, numberOfPhases, Timespan(0, traceEnd), numberOfRanks,
|
|
numberOfBankgroups, numberOfBanks, unitOfTime, clkPeriod, windowSize, controllerThread);
|
|
} else {
|
|
throw sqlException("Tracefile corrupted. No general info table",
|
|
this->pathToDB.toStdString());
|
|
}
|
|
}
|
|
|
|
CommandLengths TraceDB::getCommandLengthsFromDB()
|
|
{
|
|
unsigned NOP = getLengthOfCommandFromDB("NOP");
|
|
unsigned RD = getLengthOfCommandFromDB("RD");
|
|
unsigned WR = getLengthOfCommandFromDB("WR");
|
|
unsigned RDA = getLengthOfCommandFromDB("RDA");
|
|
unsigned WRA = getLengthOfCommandFromDB("WRA");
|
|
unsigned ACT = getLengthOfCommandFromDB("ACT");
|
|
unsigned PRE = getLengthOfCommandFromDB("PRE");
|
|
unsigned REFB = getLengthOfCommandFromDB("REFB");
|
|
unsigned PRESB = getLengthOfCommandFromDB("PRESB");
|
|
unsigned REFSB = getLengthOfCommandFromDB("REFSB");
|
|
unsigned RFMSB = getLengthOfCommandFromDB("RFMSB");
|
|
unsigned PREA = getLengthOfCommandFromDB("PREA");
|
|
unsigned REFA = getLengthOfCommandFromDB("REFA");
|
|
unsigned RFMAB = getLengthOfCommandFromDB("RFMAB");
|
|
unsigned PDEA = getLengthOfCommandFromDB("PDEA");
|
|
unsigned PDXA = getLengthOfCommandFromDB("PDXA");
|
|
unsigned PDEP = getLengthOfCommandFromDB("PDEP");
|
|
unsigned PDXP = getLengthOfCommandFromDB("PDXP");
|
|
unsigned SREFEN = getLengthOfCommandFromDB("SREFEN");
|
|
unsigned SREFEX = getLengthOfCommandFromDB("SREFEX");
|
|
|
|
return {NOP, RD, WR, RDA, WRA, ACT, PRE, REFB, PRESB, REFSB, RFMSB,
|
|
PREA, REFA, RFMAB, PDEA, PDXA, PDEP, PDXP, SREFEN, SREFEX};
|
|
}
|
|
|
|
unsigned int TraceDB::getLengthOfCommandFromDB(const std::string& command)
|
|
{
|
|
QSqlQuery query(("SELECT " + command + " FROM CommandLengths").c_str(), database);
|
|
if (query.first())
|
|
return query.value(0).toUInt();
|
|
else
|
|
{
|
|
qDebug() << "Warning: Length of command " << command.c_str() << " not present in DB, setting 1 as default.";
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
unsigned int TraceDB::getNumberOfPhases()
|
|
{
|
|
QSqlQuery query(database);
|
|
query.prepare("SELECT COUNT(ID) FROM Phases");
|
|
executeQuery(query);
|
|
|
|
query.next();
|
|
return query.value(0).toInt();
|
|
}
|
|
|
|
vector<CommentModel::Comment> TraceDB::getComments()
|
|
{
|
|
QSqlQuery query(database);
|
|
query.prepare("SELECT Time,Text From Comments");
|
|
executeQuery(query);
|
|
return parseCommentsFromQuery(query);
|
|
}
|
|
|
|
|
|
vector<CommentModel::Comment> TraceDB::getDebugMessagesInTimespan(const Timespan &span)
|
|
{
|
|
selectDebugMessagesByTimespan.bindValue(":begin", span.Begin());
|
|
selectDebugMessagesByTimespan.bindValue(":end", span.End());
|
|
executeQuery(selectDebugMessagesByTimespan);
|
|
|
|
return parseCommentsFromQuery(selectDebugMessagesByTimespan);
|
|
}
|
|
|
|
vector<CommentModel::Comment> TraceDB::getDebugMessagesInTimespan(const Timespan &span,
|
|
unsigned int limit = 50)
|
|
{
|
|
selectDebugMessagesByTimespanWithLimit.bindValue(":begin", span.Begin());
|
|
selectDebugMessagesByTimespanWithLimit.bindValue(":end", span.End());
|
|
selectDebugMessagesByTimespanWithLimit.bindValue(":limit", limit);
|
|
executeQuery(selectDebugMessagesByTimespanWithLimit);
|
|
return parseCommentsFromQuery(selectDebugMessagesByTimespanWithLimit);
|
|
}
|
|
|
|
DependencyInfos TraceDB::getDependencyInfos(DependencyInfos::Type infoType)
|
|
{
|
|
DependencyInfos dummy;
|
|
executeQuery(checkDependenciesExist);
|
|
if (!checkDependenciesExist.next() || checkDependenciesExist.value(0).toInt() != 1)
|
|
{
|
|
return dummy;
|
|
}
|
|
|
|
switch (infoType)
|
|
{
|
|
case DependencyInfos::Type::DependencyType:
|
|
executeQuery(selectDependencyTypePercentages);
|
|
return parseDependencyInfos(selectDependencyTypePercentages, infoType);
|
|
|
|
case DependencyInfos::Type::TimeDependency:
|
|
executeQuery(selectTimeDependencyPercentages);
|
|
return parseDependencyInfos(selectTimeDependencyPercentages, infoType);
|
|
|
|
case DependencyInfos::Type::DelayedPhase:
|
|
executeQuery(selectDelayedPhasePercentages);
|
|
return parseDependencyInfos(selectDelayedPhasePercentages, infoType);
|
|
|
|
case DependencyInfos::Type::DependencyPhase:
|
|
executeQuery(selectDependencyPhasePercentages);
|
|
return parseDependencyInfos(selectDependencyPhasePercentages, infoType);
|
|
}
|
|
|
|
return dummy;
|
|
}
|
|
|
|
QSqlDatabase TraceDB::getDatabase() const
|
|
{
|
|
return database;
|
|
}
|
|
|
|
/* Helpers
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
|
|
shared_ptr<Transaction> TraceDB::parseTransactionFromQuery(QSqlQuery &query)
|
|
{
|
|
auto result = parseTransactionsFromQuery(query);
|
|
if (!result.empty())
|
|
return result[0];
|
|
else
|
|
return shared_ptr<Transaction>();
|
|
}
|
|
|
|
vector<shared_ptr<Transaction>> TraceDB::parseTransactionsFromQuery(QSqlQuery &query, bool updateVisiblePhases)
|
|
{
|
|
if (updateVisiblePhases)
|
|
{
|
|
_visiblePhases.clear();
|
|
}
|
|
|
|
vector<shared_ptr<Transaction>> result;
|
|
|
|
bool firstIteration = true;
|
|
ID currentID = 0;
|
|
int i = -1;
|
|
|
|
while (query.next()) {
|
|
|
|
ID id = query.value(0).toInt();
|
|
|
|
if (currentID != id || firstIteration) {
|
|
++i;
|
|
firstIteration = false;
|
|
currentID = id;
|
|
Timespan span(query.value(1).toLongLong(), query.value(2).toLongLong());
|
|
Timespan spanOnStrobe(query.value(3).toLongLong(), query.value(4).toLongLong());
|
|
unsigned int address = query.value(5).toInt();
|
|
unsigned int burstlength = query.value(6).toInt();
|
|
unsigned int thread = query.value(7).toInt();
|
|
unsigned int channel = query.value(8).toInt();
|
|
unsigned int rank = query.value(9).toInt();
|
|
unsigned int bankgroup = query.value(10).toInt();
|
|
unsigned int bank = query.value(11).toInt();
|
|
unsigned int row = query.value(12).toInt();
|
|
unsigned int column = query.value(13).toInt();
|
|
result.push_back(shared_ptr<Transaction>(new Transaction(id, address, burstlength,
|
|
thread, channel, rank, bankgroup, bank, row, column,
|
|
span, spanOnStrobe, generalInfo->clkPeriod)));
|
|
}
|
|
|
|
unsigned int phaseID = query.value(14).toInt();
|
|
QString phaseName = query.value(15).toString();
|
|
Timespan span(query.value(16).toLongLong(), query.value(17).toLongLong());
|
|
auto phase = PhaseFactory::CreatePhase(phaseID, phaseName, span, result.at(result.size() - 1), *this);
|
|
result.at(result.size() - 1)->addPhase(phase);
|
|
|
|
if (updateVisiblePhases)
|
|
{
|
|
_visiblePhases[phaseID] = phase;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void TraceDB::mUpdateDependenciesFromQuery(QSqlQuery &query)
|
|
{
|
|
DependencyType type;
|
|
while (query.next())
|
|
{
|
|
ID delayedID = query.value(0).toInt();
|
|
ID dependencyID = query.value(4).toInt();
|
|
|
|
QString dependencyTypeStr = query.value(2).toString();
|
|
if (dependencyTypeStr == "bank")
|
|
{
|
|
type = DependencyType::Bank;
|
|
}
|
|
else if (dependencyTypeStr == "rank")
|
|
{
|
|
type = DependencyType::Rank;
|
|
}
|
|
else if (dependencyTypeStr == "interRank")
|
|
{
|
|
type = DependencyType::InterRank;
|
|
}
|
|
|
|
QString timeDependencyStr = query.value(3).toString();
|
|
|
|
if (_visiblePhases.count(delayedID) > 0)
|
|
{
|
|
|
|
if (_visiblePhases.count(dependencyID) > 0)
|
|
{
|
|
|
|
_visiblePhases[delayedID]->addDependency(std::shared_ptr<PhaseDependency>(
|
|
new PhaseDependency(type, timeDependencyStr, _visiblePhases[dependencyID])));
|
|
}
|
|
else
|
|
{
|
|
|
|
_visiblePhases[delayedID]->addDependency(
|
|
std::shared_ptr<PhaseDependency>(new PhaseDependency(type, timeDependencyStr)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO delayed phase not visible?
|
|
}
|
|
}
|
|
}
|
|
|
|
vector<CommentModel::Comment> TraceDB::parseCommentsFromQuery(QSqlQuery &query)
|
|
{
|
|
vector<CommentModel::Comment> result;
|
|
while (query.next()) {
|
|
result.push_back(CommentModel::Comment{query.value(0).toLongLong(),
|
|
query.value(1).toString()});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DependencyInfos TraceDB::parseDependencyInfos(QSqlQuery &query, const DependencyInfos::Type infoType)
|
|
{
|
|
DependencyInfos infos(infoType);
|
|
|
|
while (query.next())
|
|
{
|
|
infos.addInfo({query.value(0).toString(), query.value(1).toFloat()});
|
|
}
|
|
|
|
return infos;
|
|
}
|
|
|
|
void TraceDB::executeQuery(QSqlQuery query)
|
|
{
|
|
|
|
//query.exec returns bool indicating if the query was sucessfull
|
|
if (query.exec()) {
|
|
#ifdef printqueries
|
|
cout << queryToString(query).toStdString() << endl;
|
|
#endif
|
|
}
|
|
|
|
else {
|
|
throw sqlException( ("Query:\n " + queryToString(query) + "\n failed. Error: \n"
|
|
+
|
|
query.lastError().text()).toStdString(), this->pathToDB.toStdString());
|
|
}
|
|
}
|
|
|
|
QString TraceDB::queryToString(QSqlQuery query)
|
|
{
|
|
QString str = query.lastQuery();
|
|
QMapIterator<QString, QVariant> it(query.boundValues());
|
|
while (it.hasNext()) {
|
|
it.next();
|
|
str.replace(it.key(), it.value().toString());
|
|
}
|
|
return str;
|
|
}
|
|
|
|
|
|
void TraceDB::dropAndCreateTables()
|
|
{
|
|
executeScriptFile("common/static/createTraceDB.sql");
|
|
}
|
|
|
|
void TraceDB::executeScriptFile(QString fileName)
|
|
{
|
|
QSqlQuery query(database);
|
|
QFile scriptFile(fileName);
|
|
|
|
if (scriptFile.open(QIODevice::ReadOnly)) {
|
|
// The SQLite driver executes only a single (the first) query in the QSqlQuery
|
|
// if the script contains more queries, it needs to be splitted.
|
|
QStringList scriptQueries = QTextStream(&scriptFile).readAll().split(';');
|
|
|
|
for (QString &queryTxt : scriptQueries) {
|
|
if (queryTxt.trimmed().isEmpty()) {
|
|
continue;
|
|
}
|
|
if (!query.exec(queryTxt)) {
|
|
throw sqlException("Querry failed:" + query.lastError().text().toStdString(),
|
|
this->pathToDB.toStdString());
|
|
}
|
|
query.finish();
|
|
}
|
|
}
|
|
}
|
|
|