Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
Executable
+67
@@ -0,0 +1,67 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
# Created by Hanna Rathje, SLSE, 2017-12-14
|
||||
#
|
||||
|
||||
SET(SRCS_copy
|
||||
copy_exercise.cpp
|
||||
copy_exercise.h
|
||||
exercise_table_generator.cpp
|
||||
exercise_table_generator.h
|
||||
settings.cpp
|
||||
settings.h
|
||||
)
|
||||
NGL_ADD_LIBRARY(AAR SV WS dbAdminCopyExercise ${SRCS_copy})
|
||||
NGL_TARGET_LINK_LIBRARIES(dbAdminCopyExercise
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
Qt5::Sql
|
||||
codegen_base
|
||||
ngldb
|
||||
NGLLogger
|
||||
nglsettings
|
||||
)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(dbAdminCopyExercise
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
)
|
||||
|
||||
SET(SRCS
|
||||
local_databases_model.cpp
|
||||
local_databases_model.h
|
||||
logger.cpp
|
||||
logger.h
|
||||
db_administration.cpp
|
||||
db_administration.h
|
||||
main.cpp
|
||||
server_databases_model.cpp
|
||||
server_databases_model.h
|
||||
showLogFile.cpp
|
||||
showLogFile.h
|
||||
|
||||
)
|
||||
|
||||
NGL_WRAP_UI(SRCS ui/db_administration.ui ui/showLogFile.ui)
|
||||
|
||||
NGL_ADD_TOOL_ICON(dbAdministration)
|
||||
NGL_ADD_EXECUTABLE(AAR SV dbAdministration ${SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(dbAdministration
|
||||
dbAdminCopyExercise
|
||||
Qt5::Widgets
|
||||
Qt5::Core
|
||||
Qt5::Network
|
||||
nglapplication
|
||||
ngldb
|
||||
nglcoreapplication
|
||||
ngltools
|
||||
ngltranslator
|
||||
nglwidgets
|
||||
NGLLogger
|
||||
LtsCommandLineParser
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(dbAdministration)
|
||||
NGL_INSTALL(SV AAR FILES log4cxx_dba.props DESTINATION bin)
|
||||
|
||||
Executable
+633
@@ -0,0 +1,633 @@
|
||||
/*
|
||||
* @RDE_HEADER@
|
||||
* Copy exercise from server to evaluation server
|
||||
* $Id: copy_exercise.cpp 64999 2025-07-01 04:02:56Z fritsche_h $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/release_candidates/guez/3dws_rc/Lts/Tools/DBAdministration/copy_exercise.cpp $
|
||||
* $Author: fritsche_h $
|
||||
* Created by Christian Ehrlicher, NLSE, 2018-07-31
|
||||
*/
|
||||
|
||||
#include "copy_exercise.h"
|
||||
|
||||
#include <ngldb/dbcommon.h>
|
||||
#include <ngldb/dbconnection.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
#include <QProcess>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QSqlError>
|
||||
#include <QVariant>
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
CopyExercise::CopyExercise(NGL::INGLLogger &logger, CopyFor copyFor, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_proc(nullptr)
|
||||
, m_procPing(nullptr)
|
||||
, m_exerciseId(-1)
|
||||
, m_copyFor(copyFor)
|
||||
, m_timer(new QTimer(this))
|
||||
, m_stopPing(false)
|
||||
, m_firstPing(false)
|
||||
, m_progressBarValue(0)
|
||||
, m_logger(logger)
|
||||
{
|
||||
|
||||
QStringList args({QStringLiteral("-W 10"), // QStringLiteral("10"),
|
||||
QStringLiteral("-c 6"), //QStringLiteral("6"),
|
||||
QStringLiteral("EXCDBS01")});
|
||||
|
||||
handleProcPing(args);
|
||||
}
|
||||
|
||||
CopyExercise::~CopyExercise()
|
||||
{
|
||||
}
|
||||
|
||||
bool CopyExercise::init(int exerciseId,
|
||||
const QString &srcDbHost, const QString &srcDbName,
|
||||
const QString &dstDbHost, const QString &dstDbName)
|
||||
{
|
||||
|
||||
if (m_exerciseId > 0 )
|
||||
return true;
|
||||
|
||||
m_exerciseId = exerciseId;
|
||||
m_srcDbName = srcDbName;
|
||||
m_srcDbHost = srcDbHost;
|
||||
m_dstDbHost = dstDbHost;
|
||||
m_dstDbName = dstDbName;
|
||||
|
||||
// Server Databases
|
||||
m_dbSrv = DBConnection::open(m_logger,
|
||||
QStringLiteral("ctc_sv"),
|
||||
QStringLiteral("ctc11de"),
|
||||
QStringLiteral("QPSQL"),
|
||||
m_srcDbHost,
|
||||
m_srcDbName,
|
||||
QString(), // <-- default
|
||||
m_srcDbHost + QLatin1Char('_') + m_srcDbName + QLatin1Char('_') + QString::number(m_exerciseId));
|
||||
|
||||
if (m_copyFor == CopyForEvaluation)
|
||||
{
|
||||
m_dbEvaluation = DBConnection::open(m_logger,
|
||||
QStringLiteral("ctc_sv"),
|
||||
QStringLiteral("ctc11de"),
|
||||
QStringLiteral("QPSQL"),
|
||||
m_dstDbHost,
|
||||
m_dstDbName,
|
||||
QString(),
|
||||
m_dstDbHost + QLatin1Char('_') + m_dstDbName + QLatin1Char('_') + QString::number(m_exerciseId));
|
||||
|
||||
if (!m_dbEvaluation.isOpen())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not open DB connection to " << m_dstDbHost
|
||||
<< ", error: " << m_dbEvaluation.lastError().databaseText()
|
||||
<< ", " << m_dbEvaluation.lastError().driverText();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
else if (m_copyFor == CopyForAAR)
|
||||
{
|
||||
// Only open exercise for creating exercise user
|
||||
m_dbEvaluation = DBConnection::open(m_logger,
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("QPSQL"),
|
||||
m_dstDbHost,
|
||||
QStringLiteral("postgres"),
|
||||
QString(),
|
||||
m_dstDbHost + QLatin1Char('_') + QStringLiteral("postgres") + QLatin1Char('_') + QString::number(m_exerciseId));
|
||||
|
||||
if (!m_dbEvaluation.isOpen())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not open DB connection to " << m_dstDbHost
|
||||
<< ", error: " << m_dbEvaluation.lastError().databaseText()
|
||||
<< ", " << m_dbEvaluation.lastError().driverText();
|
||||
}
|
||||
else
|
||||
{
|
||||
NSqlQuery q(m_dbEvaluation);
|
||||
//QString user = QStringLiteral("ets_ex_") + QString::number(m_exerciseId);
|
||||
QString user = QStringLiteral("ets_ex_00");
|
||||
QString stmt = QStringLiteral("SELECT create_user_if_not_exists('") + user + QStringLiteral("')");
|
||||
if (!q.exec(stmt))
|
||||
ERROR_LOG(m_logger) << "Error while executing stmt: " << stmt << " error: " << m_dbEvaluation.lastError().databaseText();
|
||||
else
|
||||
INFO_LOG(m_logger) << "Created User " << user;
|
||||
m_dbEvaluation.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!m_dbSrv.isOpen())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not open DB connection to " << m_srcDbHost
|
||||
<< ", error: " << m_dbSrv.lastError().databaseText()
|
||||
<< ", " << m_dbSrv.lastError().driverText();
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Successfully initialized database connections";
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyExercise::setDownloadScriptIds(const QVector<int> &downloadScriptIds)
|
||||
{
|
||||
m_downloadScriptIds = downloadScriptIds;
|
||||
}
|
||||
|
||||
bool CopyExercise::doCopy(int exerciseId)
|
||||
{
|
||||
m_firstPing = true;
|
||||
onPingStart();
|
||||
|
||||
if (exerciseId > 0)
|
||||
m_exerciseId = exerciseId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyExercise::dropDb()
|
||||
{
|
||||
const QString dbName = QStringLiteral("lts_db_") + QString::number(m_exerciseId);
|
||||
|
||||
INFO_LOG(m_logger) << "Database to be dropped : " << dbName;
|
||||
|
||||
const QStringList args({QStringLiteral("-U"),
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("-h"),
|
||||
QStringLiteral("localhost"),
|
||||
dbName});
|
||||
|
||||
handleProcInit(QStringLiteral("dropdb"), args);
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &CopyExercise::onDropDbFinished2);
|
||||
|
||||
m_proc->start();
|
||||
}
|
||||
|
||||
bool CopyExercise::runPgDump()
|
||||
{
|
||||
const QString schema = DBCommon::getExerciseSchemaName(m_exerciseId);
|
||||
|
||||
QString stmt = QStringLiteral("select sum(pg_total_relation_size(quote_ident(schemaname) || '.' || quote_ident(tablename)))::bigint from pg_tables where schemaname IN ('") + schema +
|
||||
QStringLiteral("','exm','asm', 'avm', 'bdv', 'core', 'flm', 'aes', 'ism', 'mdm', 'msg', 'opm', 'ppm', 'srm', 'gna', 'tab', 'whg')");
|
||||
|
||||
|
||||
DEBUG_LOG(m_logger) << "stmt: " << stmt;
|
||||
NSqlQuery q(m_dbSrv);
|
||||
if (!q.execAndFetch(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while estimating size of database dump errror: " << m_dbSrv.lastError().databaseText();
|
||||
m_stopPing = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
m_sizePgDump = q.value(0).toLongLong();
|
||||
|
||||
double seconds = m_sizePgDump / 1024 / 100 * 0.0015;
|
||||
|
||||
INFO_LOG(m_logger) << "Size database dump: " << m_sizePgDump;
|
||||
INFO_LOG(m_logger) << " seconds: " << seconds;
|
||||
|
||||
m_timer->setInterval(seconds * 1000);
|
||||
connect(m_timer, &QTimer::timeout, this, &CopyExercise::onTimeoutTimer);
|
||||
|
||||
|
||||
// start process
|
||||
const QStringList args({
|
||||
QStringLiteral("-n"), schema,
|
||||
QStringLiteral("-n"), QStringLiteral("public"),
|
||||
QStringLiteral("-n"), QStringLiteral("exm"),
|
||||
QStringLiteral("-n"), QStringLiteral("asm"),
|
||||
QStringLiteral("-n"), QStringLiteral("avm"),
|
||||
QStringLiteral("-n"), QStringLiteral("bdv"),
|
||||
QStringLiteral("-n"), QStringLiteral("core"),
|
||||
QStringLiteral("-n"), QStringLiteral("flm"),
|
||||
QStringLiteral("-n"), QStringLiteral("aes"),
|
||||
QStringLiteral("-n"), QStringLiteral("ism"),
|
||||
QStringLiteral("-n"), QStringLiteral("mdm"),
|
||||
QStringLiteral("-n"), QStringLiteral("msg"),
|
||||
QStringLiteral("-n"), QStringLiteral("opm"),
|
||||
QStringLiteral("-n"), QStringLiteral("pdm"),
|
||||
QStringLiteral("-n"), QStringLiteral("ppm"),
|
||||
QStringLiteral("-n"), QStringLiteral("srm"),
|
||||
QStringLiteral("-n"), QStringLiteral("gna"),
|
||||
QStringLiteral("-n"), QStringLiteral("tab"),
|
||||
QStringLiteral("-n"), QStringLiteral("whg"),
|
||||
|
||||
QStringLiteral("-U"), QStringLiteral("postgres"),
|
||||
QStringLiteral("-Fc"),
|
||||
QStringLiteral("-f"), getDumpFile(),
|
||||
QStringLiteral("-h"), m_srcDbHost,
|
||||
m_srcDbName
|
||||
});
|
||||
|
||||
handleProcInit(QStringLiteral("pg_dump"), args);
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &CopyExercise::onPgDumpFinished);
|
||||
|
||||
m_proc->start();
|
||||
m_progressBarValue = 1;
|
||||
m_timer->start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyExercise::onTimeoutTimer()
|
||||
{
|
||||
INFO_LOG(m_logger) << "in onTimeoutTimer()";
|
||||
|
||||
m_progressBarValue += 1;
|
||||
INFO_LOG(m_logger) << "emit : " << m_progressBarValue;
|
||||
emit nextProgress(m_progressBarValue);
|
||||
}
|
||||
|
||||
void CopyExercise::onPgDumpFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
m_timer->stop();
|
||||
|
||||
// 1/4 done
|
||||
m_progressBarValue = 25;
|
||||
emit nextProgress(m_progressBarValue);
|
||||
|
||||
if (!checkExitStatus(QStringLiteral("onPgDumpFinished"), exitCode, exitStatus))
|
||||
{
|
||||
QFile::remove(getDumpFile());
|
||||
dropDb();
|
||||
return;
|
||||
}
|
||||
|
||||
const QString dbName = QStringLiteral("lts_db_") + QString::number(m_exerciseId);
|
||||
|
||||
const QStringList args({QStringLiteral("-U"),
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("-h"),
|
||||
m_dstDbHost,
|
||||
dbName});
|
||||
|
||||
handleProcInit(QStringLiteral("dropdb"), args);
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &CopyExercise::onDropDbFinished);
|
||||
|
||||
m_proc->start();
|
||||
}
|
||||
|
||||
void CopyExercise::onDropDbFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
INFO_LOG(m_logger) << "onDropDbFinished: exitCode: " << exitCode << ", exitStatus: " << exitStatus;
|
||||
m_progressBarValue = 30;
|
||||
emit nextProgress(m_progressBarValue);
|
||||
|
||||
const QString dbName = QStringLiteral("lts_db_") + QString::number(m_exerciseId);
|
||||
const QStringList args({QStringLiteral("-U"),
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("-T"),
|
||||
QStringLiteral("template2"),
|
||||
QStringLiteral("-h"),
|
||||
m_dstDbHost,
|
||||
dbName});
|
||||
|
||||
handleProcInit(QStringLiteral("createdb"), args);
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &CopyExercise::onCreateDbFinished);
|
||||
|
||||
m_proc->start();
|
||||
}
|
||||
|
||||
void CopyExercise::onDropDbFinished2(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
|
||||
ERROR_LOG(m_logger) << "onDropDbFinished2: exitCode: " << exitCode << ", exitStatus: " << exitStatus;
|
||||
emit copyDbFailed();
|
||||
}
|
||||
|
||||
void CopyExercise::onCreateDbFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
INFO_LOG(m_logger) << "onCreateDbFinished: exitCode: " << exitCode << ", exitStatus: " << exitStatus;
|
||||
m_progressBarValue = 35;
|
||||
emit nextProgress(m_progressBarValue);
|
||||
|
||||
if (exitCode > 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Exercise " << m_exerciseId << " already exists";
|
||||
QFile::remove(getDumpFile());
|
||||
emit copyDbFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
const QString dbName = QStringLiteral("lts_db_") + QString::number(m_exerciseId);
|
||||
const QStringList args({QStringLiteral("-U"),
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("-h"),
|
||||
m_dstDbHost,
|
||||
QStringLiteral("-d"),
|
||||
dbName,
|
||||
QStringLiteral("-j"),
|
||||
QStringLiteral("4"),
|
||||
getDumpFile(),
|
||||
});
|
||||
|
||||
handleProcInit(QStringLiteral("pg_restore"), args);
|
||||
if (m_copyFor == CopyForEvaluation)
|
||||
{
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &CopyExercise::onPsqlFinishedForEvaluation);
|
||||
}
|
||||
else
|
||||
{
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &CopyExercise::onPsqlFinishedForAAR);
|
||||
}
|
||||
|
||||
double seconds = m_sizePgDump / 1024 / 100 * 0.001;
|
||||
INFO_LOG(m_logger) << " seconds: " << seconds;
|
||||
|
||||
m_timer->setInterval(seconds * 1000);
|
||||
m_timer->start();
|
||||
|
||||
m_proc->start();
|
||||
}
|
||||
|
||||
void CopyExercise::onPsqlFinishedForEvaluation(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
m_timer->stop();
|
||||
m_progressBarValue = 75;
|
||||
emit nextProgress(m_progressBarValue);
|
||||
|
||||
if (!checkExitStatus(QStringLiteral("onPsqlFinishedForEvaluation"), exitCode, exitStatus))
|
||||
return;
|
||||
|
||||
if ( exitStatus == QProcess::ExitStatus::NormalExit )
|
||||
QFile::remove(getDumpFile());
|
||||
|
||||
// get exercise data from db
|
||||
QVariant exName, exStartTime, exEndTime;
|
||||
{
|
||||
NSqlQuery q(m_dbSrv);
|
||||
|
||||
QString stmt = QStringLiteral("SELECT name, begin_time, end_time FROM exm.exercise WHERE id = ") + QString::number(m_exerciseId);
|
||||
if (q.execAndFetch(stmt))
|
||||
{
|
||||
int i = 0;
|
||||
exName = q.value(i++);
|
||||
exStartTime = q.value(i++);
|
||||
exEndTime = q.value(i++);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while reading exercise info for exercise " << m_exerciseId << " from source database"
|
||||
<< ", error: " << q.lastError().databaseText()
|
||||
<< ", " << q.lastError().driverText()
|
||||
<< ", stmt: " << stmt;
|
||||
emit copyDbFailed();
|
||||
m_stopPing = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NSqlQuery q(m_dbEvaluation);
|
||||
|
||||
QString stmt = QStringLiteral("INSERT INTO local_databases (name, db_name, begin_time, end_time) "
|
||||
"VALUES (:name, :dbName, :beginTime, :endTime) ");
|
||||
|
||||
q.prepare(stmt);
|
||||
q.bindValue(QStringLiteral(":name"), exName);
|
||||
QString dbName = QStringLiteral("lts_db_") + QString::number(m_exerciseId);
|
||||
q.bindValue(QStringLiteral(":dbName"), dbName);
|
||||
q.bindValue(QStringLiteral(":beginTime"), exStartTime);
|
||||
q.bindValue(QStringLiteral(":endTime"), exEndTime);
|
||||
|
||||
if (!q.exec())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while inserting data in local_databases: exerciseId = " << m_exerciseId
|
||||
<< ", error: " << q.lastError().databaseText()
|
||||
<< ", " << q.lastError().driverText();
|
||||
emit copyDbFailed();
|
||||
}
|
||||
else
|
||||
{
|
||||
emit copyDbFinished();
|
||||
}
|
||||
m_stopPing = true;
|
||||
m_dbEvaluation.close();
|
||||
}
|
||||
|
||||
void CopyExercise::onPsqlFinishedForAAR(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
m_timer->stop();
|
||||
m_progressBarValue = 75;
|
||||
emit nextProgress(m_progressBarValue);
|
||||
|
||||
if (!checkExitStatus(QStringLiteral("onPsqlFinishedForAAR"), exitCode, exitStatus))
|
||||
return;
|
||||
|
||||
if ( exitStatus == QProcess::ExitStatus::NormalExit )
|
||||
QFile::remove(getDumpFile());
|
||||
|
||||
//init procedures in schema public
|
||||
const QString fileName = QStringLiteral("/shd/CTC/AAR/bin/test/init_db_procedures.sql");
|
||||
const QStringList args({QStringLiteral("-U"),
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("-h"),
|
||||
m_dstDbHost,
|
||||
QStringLiteral("-d"),
|
||||
m_dstDbName,
|
||||
QStringLiteral("-f"),
|
||||
fileName
|
||||
});
|
||||
handleProcInit(QStringLiteral("psql"), args);
|
||||
//init procedures in schema public
|
||||
|
||||
// now open the downloaded database
|
||||
if (!m_dbEvaluation.isOpen())
|
||||
{
|
||||
m_dbEvaluation = DBConnection::open(m_logger,
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("QPSQL"),
|
||||
m_dstDbHost,
|
||||
m_dstDbName,
|
||||
QString(),
|
||||
m_dstDbHost + QLatin1Char('_') + m_dstDbName + QLatin1Char('_') + QString::number(m_exerciseId));
|
||||
|
||||
if (!m_dbEvaluation.isOpen())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not open DB connection to " << m_dstDbHost
|
||||
<< ", error: " << m_dbEvaluation.lastError().databaseText()
|
||||
<< ", " << m_dbEvaluation.lastError().driverText();
|
||||
emit copyDbFailed();
|
||||
m_stopPing = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NSqlQuery q(m_dbEvaluation);
|
||||
|
||||
const QString schema = DBCommon::getExerciseSchemaName(m_exerciseId);
|
||||
QStringList downloadScriptIds;
|
||||
downloadScriptIds.reserve(m_downloadScriptIds.size());
|
||||
for (int id : qAsConst(m_downloadScriptIds))
|
||||
downloadScriptIds.push_back(QString::number(id));
|
||||
|
||||
QString stmt = QLatin1String("DELETE FROM ") + schema + QLatin1String(".pre_presentation WHERE id not in (") + downloadScriptIds.join(QLatin1Char(',')) + QLatin1Char(')');
|
||||
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while deleting scripts from database";
|
||||
emit copyDbFailed();
|
||||
}
|
||||
else
|
||||
{
|
||||
// stmt = QLatin1String("DELETE FROM exm.exercise WHERE id != ") + QString::number(m_exerciseId);
|
||||
// deleting foreign key will delete all dependences in cascade, so all FLM data for that exercise
|
||||
stmt = QLatin1String("UPDATE exm.exercise SET exercise_state_id = 6 WHERE id != ") + QString::number(m_exerciseId);
|
||||
DEBUG_LOG(m_logger) << "Executing statement: " << stmt;
|
||||
if (!q.exec(stmt))
|
||||
ERROR_LOG(m_logger) << "Error on updating exm.exercise " << m_dbEvaluation.lastError().databaseText();
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Statement succesfully executed";
|
||||
|
||||
stmt = QLatin1String("GRANT USAGE ON SCHEMA PUBLIC TO ets_ro;");
|
||||
DEBUG_LOG(m_logger) << "Executing statement: " << stmt;
|
||||
if (!q.exec(stmt))
|
||||
ERROR_LOG(m_logger) << "Error on grant usage " << m_dbEvaluation.lastError().databaseText();
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Statement succesfully executed";
|
||||
|
||||
stmt = QLatin1String("GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO ets_ro;");
|
||||
DEBUG_LOG(m_logger) << "Executing statement: " << stmt;
|
||||
if (!q.exec(stmt))
|
||||
ERROR_LOG(m_logger) << "Error on grant execute " << m_dbEvaluation.lastError().databaseText();
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Statement succesfully executed";
|
||||
|
||||
emit copyDbFinished();
|
||||
}
|
||||
m_stopPing = true;
|
||||
m_dbEvaluation.close();
|
||||
}
|
||||
|
||||
bool CopyExercise::checkExitStatus(const QString &procName, int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
if (exitCode > 0)
|
||||
{
|
||||
NOTICE_LOG(m_logger) << procName << ": exitCode: " << exitCode << ", exitStatus: " << exitStatus;
|
||||
WARNING_LOG(m_logger) << m_proc->readAllStandardError() << m_proc->readAllStandardOutput();
|
||||
m_stopPing = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyExercise::handleProcPing(const QStringList &args)
|
||||
{
|
||||
if (m_procPing)
|
||||
{
|
||||
m_procPing->disconnect(this);
|
||||
m_procPing->deleteLater();
|
||||
}
|
||||
m_procPing = new QProcess(this);
|
||||
QString errStr;
|
||||
const QString exePath = NGL::postgresExecutablePath(QStringLiteral("ping"), errStr);
|
||||
if (!errStr.isEmpty())
|
||||
WARNING_LOG(m_logger) << errStr;
|
||||
INFO_LOG(m_logger) << "Starting process '" << exePath << "' with args '"
|
||||
<< args.join(QLatin1Char(' ')) << "'";
|
||||
m_procPing->setProgram(exePath);
|
||||
m_procPing->setArguments(args);
|
||||
connect(m_procPing, &QProcess::errorOccurred,
|
||||
this, &CopyExercise::onErrorOccured);
|
||||
connect(m_procPing, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &CopyExercise::onPingFinished);
|
||||
|
||||
}
|
||||
|
||||
void CopyExercise::onPingStart()
|
||||
{
|
||||
m_stopPing = false;
|
||||
m_procPing->start();
|
||||
INFO_LOG(m_logger) << "ping started ";
|
||||
}
|
||||
|
||||
void CopyExercise::onPingFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
if (exitCode > 0)
|
||||
DEBUG_LOG(m_logger) << "got ping result with exitCode != 0. exitCode: " << exitCode << ", exitStatus: " << exitStatus;
|
||||
else
|
||||
{
|
||||
if (m_firstPing)
|
||||
{
|
||||
m_firstPing = false;
|
||||
if (!runPgDump())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error running pg_dump for exercise " << m_exerciseId;
|
||||
emit copyDbFailed();
|
||||
m_stopPing = true;
|
||||
}
|
||||
}
|
||||
if (!m_stopPing)
|
||||
QTimer::singleShot(2000, this, &CopyExercise::onPingStart);
|
||||
}
|
||||
}
|
||||
|
||||
void CopyExercise::stopPing()
|
||||
{
|
||||
m_stopPing = true;
|
||||
}
|
||||
|
||||
void CopyExercise::handleProcInit(const QString &program, const QStringList &args)
|
||||
{
|
||||
if (m_proc)
|
||||
{
|
||||
m_proc->disconnect(this);
|
||||
m_proc->deleteLater();
|
||||
}
|
||||
m_proc = new QProcess(this);
|
||||
QString errStr;
|
||||
const QString exePath = NGL::postgresExecutablePath(program, errStr);
|
||||
if (!errStr.isEmpty())
|
||||
WARNING_LOG(m_logger) << errStr;
|
||||
INFO_LOG(m_logger) << "Starting process '" << exePath << "' with args '"
|
||||
<< args.join(QLatin1Char(' ')) << "'";
|
||||
m_proc->setProgram(exePath);
|
||||
m_proc->setArguments(args);
|
||||
connect(m_proc, &QProcess::errorOccurred,
|
||||
this, &CopyExercise::onErrorOccured);
|
||||
}
|
||||
|
||||
void CopyExercise::handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
if (!m_proc)
|
||||
return;
|
||||
if (exitCode != 0 || exitStatus != 0)
|
||||
{
|
||||
QByteArray out = m_proc->readAllStandardError();
|
||||
if (!out.isEmpty())
|
||||
out += '\n';
|
||||
out += m_proc->readAllStandardOutput();
|
||||
ERROR_LOG(m_logger) << "Process finished - exitCode: " << exitCode << ", exitStatus = " << exitStatus << ", " << out;
|
||||
}
|
||||
m_proc->disconnect(this);
|
||||
m_proc->deleteLater();
|
||||
m_proc = nullptr;
|
||||
}
|
||||
|
||||
void CopyExercise::onErrorOccured(QProcess::ProcessError error)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "onErrorOccured: error: " << error << ", " << m_proc->readAllStandardOutput() << ", " << m_proc->readAllStandardError();
|
||||
m_timer->stop();
|
||||
}
|
||||
|
||||
QString CopyExercise::getDumpFile() const
|
||||
{
|
||||
return QDir::tempPath() + QLatin1Char('/') + m_srcDbName + QLatin1Char('_')+ QString::number(m_exerciseId) + QStringLiteral(".dump");
|
||||
}
|
||||
|
||||
} // namespace DBAdministration
|
||||
Executable
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* @RDE_HEADER@
|
||||
* Copy exercise from server to evaluation server
|
||||
* $Id: copy_exercise.h 64999 2025-07-01 04:02:56Z fritsche_h $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/release_candidates/guez/3dws_rc/Lts/Tools/DBAdministration/copy_exercise.h $
|
||||
* $Author: fritsche_h $
|
||||
* Created by Christian Ehrlicher, NLSE, 2018-07-31
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QSqlDatabase>
|
||||
#include <QVector>
|
||||
#include <QTimer>
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
class CopyExercise : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
enum CopyFor
|
||||
{
|
||||
CopyForEvaluation = 0,
|
||||
CopyForAAR = 1
|
||||
};
|
||||
explicit CopyExercise(NGL::INGLLogger &logger, CopyFor copyFor, QObject *parent = nullptr);
|
||||
~CopyExercise();
|
||||
|
||||
bool init(int exerciseId,
|
||||
const QString &srcDbHost, const QString &srcDbName,
|
||||
const QString &dstDbHost, const QString &dstDbName);
|
||||
bool doCopy(int exerciseId = 0);
|
||||
void setDownloadScriptIds(const QVector<int> &downloadScriptIds);
|
||||
void stopPing();
|
||||
|
||||
QSqlDatabase serverDb() const { return m_dbSrv; }
|
||||
QSqlDatabase evaluationDb() const { return m_dbEvaluation; }
|
||||
void handleProcInit(const QString &program, const QStringList &args);
|
||||
void handleProcPing(const QStringList &args);
|
||||
Q_SIGNALS:
|
||||
void copyDbFailed();
|
||||
void copyDbFinished();
|
||||
void nextProgress(int);
|
||||
|
||||
private:
|
||||
bool runPgDump();
|
||||
void onPgDumpFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onCreateDbFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onDropDbFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onDropDbFinished2(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onPsqlFinishedForEvaluation(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onPsqlFinishedForAAR(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onPingFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
bool checkExitStatus(const QString &procName, int exitCode, QProcess::ExitStatus exitStatus);
|
||||
QString getDumpFile() const;
|
||||
|
||||
void handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onErrorOccured(QProcess::ProcessError error);
|
||||
void onTimeoutTimer();
|
||||
void onPingStart();
|
||||
void dropDb();
|
||||
void onTimerCheckFailed();
|
||||
|
||||
|
||||
private:
|
||||
QString m_srcDbHost;
|
||||
QString m_srcDbName;
|
||||
QString m_dstDbHost;
|
||||
QString m_dstDbName;
|
||||
QSqlDatabase m_dbSrv;
|
||||
QSqlDatabase m_dbEvaluation;
|
||||
QProcess *m_proc;
|
||||
QProcess *m_procPing;
|
||||
int m_exerciseId;
|
||||
CopyFor m_copyFor;
|
||||
QVector<int> m_downloadScriptIds;
|
||||
QTimer* m_timer;
|
||||
bool m_stopPing;
|
||||
bool m_firstPing;
|
||||
int m_progressBarValue;
|
||||
qint64 m_sizePgDump{0};
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace DBAdministration
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
|
||||
DROP TABLE IF EXISTS local_databases;
|
||||
CREATE TABLE local_databases (
|
||||
|
||||
id serial,
|
||||
name text,
|
||||
db_name text,
|
||||
begin_time bigint,
|
||||
end_time bigint
|
||||
|
||||
);
|
||||
|
||||
GRANT INSERT, UPDATE, DELETE, SELECT ON local_databases TO ets_ro;
|
||||
GRANT USAGE,SELECT ON local_databases_id_seq TO ets_ro;
|
||||
|
||||
--insert into local_databases (name, db_name, begin_time, end_time) values ( 'Test1', 'lts_ets', 1000, 2000);
|
||||
|
||||
+441
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* @RDE_HEADER@
|
||||
* <short description>
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Malte Schröder, SLSE, 2016-06-08
|
||||
*/
|
||||
|
||||
#include "db_administration.h"
|
||||
#include "ui_db_administration.h"
|
||||
#include "server_databases_model.h"
|
||||
#include "local_databases_model.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <ngldb/dbconnection.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QTimer>
|
||||
#include <QMenu>
|
||||
#include <QSettings>
|
||||
#include <QDir>
|
||||
#include <QNetworkInterface>
|
||||
#include <QHostInfo>
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
|
||||
DBAdministration::DBAdministration(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, m_ui(new Ui::DBAdministration)
|
||||
, m_proc(nullptr)
|
||||
, m_progressDialog(nullptr)
|
||||
, m_timer(nullptr)
|
||||
, m_menuBar(new QMenuBar(this))
|
||||
, m_showLog(new ShowLogFile)
|
||||
, m_copyExercise(new CopyExercise(getLogger("CopyExercise"), CopyExercise::CopyForEvaluation, this))
|
||||
, m_bRunsOnEvaluationServer(checkRunsOnEvaluationServer())
|
||||
, m_logger(getLogger("DBAdministration"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_serverDatabasesModel = new ServerDatabasesModel(this);
|
||||
m_proxyModelServer = new ServerDatabasesProxyModel(this);
|
||||
m_proxyModelServer->setSourceModel(m_serverDatabasesModel);
|
||||
m_ui->tableViewServerDatabases->setModel(m_proxyModelServer);
|
||||
|
||||
m_localDatabasesModel = new LocalDatabasesModel(this);
|
||||
m_proxyModelLocal = new LocalDatabasesProxyModel(this);
|
||||
m_proxyModelLocal->setSourceModel(m_localDatabasesModel);
|
||||
m_ui->tableViewLocalDatabases->setModel(m_proxyModelLocal);
|
||||
|
||||
connect(m_ui->pbCopy, &QPushButton::clicked, this, &DBAdministration::onCopyButtonClicked);
|
||||
connect(m_ui->pbClose, &QPushButton::clicked, this, &DBAdministration::onClosedClicked);
|
||||
connect(m_ui->pbRemove, &QPushButton::clicked, this, &DBAdministration::onRemoveClicked);
|
||||
connect(m_ui->pbActivate, &QPushButton::clicked, this, &DBAdministration::onActivateClicked);
|
||||
|
||||
connect(m_ui->tableViewServerDatabases->selectionModel(), &QItemSelectionModel::selectionChanged, this, &DBAdministration::enaDisa);
|
||||
connect(m_ui->tableViewLocalDatabases->selectionModel(), &QItemSelectionModel::selectionChanged, this, &DBAdministration::enaDisa);
|
||||
|
||||
setWindowTitle(QLatin1String("DBAdministration"));
|
||||
|
||||
connect(m_ui->actionShow, &QAction::triggered, this, &DBAdministration::onShowLogFile);
|
||||
connect(m_ui->actionStart, &QAction::triggered, this, &DBAdministration::onStartApp);
|
||||
connect(m_ui->actionStop, &QAction::triggered, this, &DBAdministration::onStopApp);
|
||||
|
||||
connect(m_copyExercise, &CopyExercise::copyDbFailed, this, &DBAdministration::onCopyDbFailed);
|
||||
connect(m_copyExercise, &CopyExercise::copyDbFinished, this, &DBAdministration::onCopyDbFinished);
|
||||
|
||||
m_ui->actionStart->setEnabled(m_bRunsOnEvaluationServer);
|
||||
m_ui->actionStop->setEnabled(m_bRunsOnEvaluationServer);
|
||||
m_ui->menuService_Management->setEnabled(m_bRunsOnEvaluationServer);
|
||||
|
||||
enaDisa();
|
||||
}
|
||||
|
||||
DBAdministration::~DBAdministration()
|
||||
{
|
||||
delete m_ui;
|
||||
delete m_serverDatabasesModel;
|
||||
delete m_progressDialog;
|
||||
delete m_timer;
|
||||
delete m_menuBar;
|
||||
delete m_showLog;
|
||||
|
||||
if (m_proc)
|
||||
m_proc->deleteLater();
|
||||
}
|
||||
|
||||
bool DBAdministration::init()
|
||||
{
|
||||
if (!m_copyExercise->init(0,
|
||||
Settings::serverDatabaseHost(),
|
||||
Settings::serverDatabaseName(),
|
||||
Settings::evaluationDatabaseHost(),
|
||||
Settings::evaluationDatabaseName()))
|
||||
return false;
|
||||
m_serverDatabasesModel->initModel(m_copyExercise->serverDb());
|
||||
m_localDatabasesModel->initModel(m_copyExercise->evaluationDb());
|
||||
m_ui->tableViewServerDatabases->resizeColumnsToContents();
|
||||
m_ui->tableViewLocalDatabases->resizeColumnsToContents();
|
||||
return true;
|
||||
}
|
||||
|
||||
void DBAdministration::onClosedClicked()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void DBAdministration::onRemoveClicked()
|
||||
{
|
||||
disableButtons();
|
||||
|
||||
m_localDatabaseToRemove = m_localDatabasesModel->getRowData(m_ui->tableViewLocalDatabases->currentIndex().row());
|
||||
|
||||
QString strMsg = QStringLiteral("Do you really want to remove the database '%1'?").arg (m_localDatabaseToRemove.dbName);
|
||||
int result = QMessageBox::question(this, tr("Remove Database"), strMsg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
if (result == QMessageBox::No)
|
||||
{
|
||||
enableButtons();
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "onRemoveClicked: dbName = " << m_localDatabaseToRemove.dbName;
|
||||
|
||||
const QStringList args({QStringLiteral("-U"),
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("-h"),
|
||||
Settings::evaluationDatabaseHost(),
|
||||
m_localDatabaseToRemove.dbName
|
||||
});
|
||||
|
||||
QString errStr;
|
||||
const QString exePath = NGL::postgresExecutablePath(QStringLiteral("dropdb"), errStr);
|
||||
if (!errStr.isEmpty())
|
||||
WARNING_LOG(m_logger) << errStr;
|
||||
|
||||
handleProcInit(exePath, args);
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &DBAdministration::onDropDbFinished);
|
||||
|
||||
// start process
|
||||
m_proc->start();
|
||||
}
|
||||
|
||||
void DBAdministration::onActivateClicked()
|
||||
{
|
||||
LocalExercise le = m_localDatabasesModel->getRowData(m_ui->tableViewLocalDatabases->currentIndex().row());
|
||||
|
||||
QString strMsg = QStringLiteral("Do you really want to active database '%1'?").arg(le.dbName);
|
||||
int result = QMessageBox::question(this, tr("Activate Database"), strMsg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
if (result == QMessageBox::No)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "onActivateClicked: dbName = " << le.dbName;
|
||||
|
||||
QString configFileName = QStringLiteral("/lts-cc.conf");
|
||||
QString filename;
|
||||
QScopedPointer<QSettings> settings;
|
||||
|
||||
filename = QDir::homePath() + configFileName;
|
||||
if (QFile::exists(filename))
|
||||
{
|
||||
settings.reset(new QSettings(filename, QSettings::Format::IniFormat));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
filename = QStringLiteral("/etc") + configFileName;
|
||||
#else
|
||||
filename = QCoreApplication::applicationDirPath() + QLatin1String("\\") + configFileName;
|
||||
#endif
|
||||
if (QFile::exists(filename))
|
||||
{
|
||||
settings.reset(new QSettings(filename, QSettings::Format::IniFormat));
|
||||
}
|
||||
else
|
||||
// fallback
|
||||
settings.reset(new QSettings(QLatin1String("RDE"), QLatin1String("LTS-CC")));
|
||||
}
|
||||
|
||||
ERROR_LOG(m_logger) << "FileName: " << filename;
|
||||
settings->setValue(QStringLiteral("Global") + QStringLiteral("/DatabaseName"), le.dbName);
|
||||
|
||||
}
|
||||
|
||||
void DBAdministration::enaDisa()
|
||||
{
|
||||
if (!m_ui)
|
||||
return;
|
||||
int selected = m_ui->tableViewServerDatabases->selectionModel()->selectedRows().size();
|
||||
m_ui->pbCopy->setEnabled(selected > 0);
|
||||
|
||||
selected = m_ui->tableViewLocalDatabases->selectionModel()->selectedRows().size();
|
||||
m_ui->pbRemove->setEnabled(selected > 0);
|
||||
m_ui->pbActivate->setEnabled(selected > 0 && m_bRunsOnEvaluationServer);
|
||||
}
|
||||
|
||||
void DBAdministration::onCopyButtonClicked()
|
||||
{
|
||||
disableButtons();
|
||||
auto exercise = m_serverDatabasesModel->getRowData(m_proxyModelServer->mapToSource(m_ui->tableViewServerDatabases->currentIndex()).row());
|
||||
m_copyExercise->doCopy(exercise.id);
|
||||
if (!m_progressDialog)
|
||||
m_progressDialog = new QProgressDialog(this);
|
||||
m_progressDialog->setLabelText(tr("Copying database..."));
|
||||
m_progressDialog->setMinimum(0);
|
||||
m_progressDialog->setMaximum(0);
|
||||
m_progressDialog->show();
|
||||
}
|
||||
|
||||
void DBAdministration::onDropDbFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
INFO_LOG(m_logger) << "onDropDbFinished: exitCode: " << exitCode << ", exitStatus: " << exitStatus;
|
||||
bool bRemoveLocal = true;
|
||||
|
||||
if (exitCode > 0)
|
||||
{
|
||||
const QString str = QString::fromLocal8Bit(m_proc->readAllStandardError()) + QLatin1Char('\n') +
|
||||
QString::fromLocal8Bit(m_proc->readAllStandardOutput());
|
||||
ERROR_LOG(m_logger) << "Can not drop database: " << str;
|
||||
|
||||
QString db0 = QLatin1String("ERROR: database \"")+m_localDatabaseToRemove.dbName+QLatin1String("\" does not exist");
|
||||
if (!str.contains(db0))
|
||||
{
|
||||
bRemoveLocal = false;
|
||||
QMessageBox::critical(this, tr ("Remove Database"), tr("Database cannot be removed:\n%1.").arg(str), QMessageBox::Ok);
|
||||
}
|
||||
}
|
||||
|
||||
if (bRemoveLocal)
|
||||
{
|
||||
NSqlQuery q(m_copyExercise->evaluationDb());
|
||||
QString stmt = QStringLiteral("DELETE FROM local_databases WHERE id = ") + QString::number(m_localDatabaseToRemove.id);
|
||||
if (!q.exec(stmt))
|
||||
QMessageBox::critical(this, tr ("Remove Database"), tr("Database entry cannot be removed."), QMessageBox::Ok);
|
||||
else
|
||||
{
|
||||
m_localDatabasesModel->initModel(m_copyExercise->evaluationDb());
|
||||
m_ui->tableViewLocalDatabases->resizeColumnsToContents();
|
||||
}
|
||||
m_localDatabaseToRemove = LocalExercise();
|
||||
}
|
||||
enableButtons();
|
||||
}
|
||||
|
||||
void DBAdministration::onErrorOccured(QProcess::ProcessError error)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "error: " << error;
|
||||
}
|
||||
|
||||
void DBAdministration::incrementProgressBar()
|
||||
{
|
||||
m_progressDialog->setValue(m_progressDialog->value()+1);
|
||||
}
|
||||
|
||||
void DBAdministration::onShowLogFile()
|
||||
{
|
||||
ERROR_LOG(m_logger) << "IN onShowLogFile";
|
||||
|
||||
if (!m_showLog->init())
|
||||
{
|
||||
QMessageBox::critical(this, tr ("Show Logfile"), tr("Logfile does not exist."), QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
m_showLog->show();
|
||||
}
|
||||
|
||||
void DBAdministration::onStartApp()
|
||||
{
|
||||
if (!m_bRunsOnEvaluationServer)
|
||||
return;
|
||||
handleProcInit(QStringLiteral("ps"), {QStringLiteral("aux")});
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &DBAdministration::onPsauxFinished);
|
||||
m_proc->start();
|
||||
}
|
||||
|
||||
void DBAdministration::onPsauxFinished()
|
||||
{
|
||||
enableButtons();
|
||||
QByteArray output = m_proc->readAllStandardOutput();
|
||||
|
||||
if (output.contains("svcServiceManagement"))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "ServiceManagement already started";
|
||||
QMessageBox::critical(this, tr ("Service Management"), tr("Service Management already started."), QMessageBox::Ok);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Start svcServiceManagement";
|
||||
handleProcInit(QCoreApplication::applicationDirPath() + QStringLiteral("/svcServiceManagement"), {QStringLiteral("-z")});
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &DBAdministration::onStartAppFinished);
|
||||
m_proc->start();
|
||||
}
|
||||
}
|
||||
|
||||
void DBAdministration::onStartAppFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
handleProcFinished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void DBAdministration::onStopApp()
|
||||
{
|
||||
if (!m_bRunsOnEvaluationServer)
|
||||
return;
|
||||
disableButtons();
|
||||
handleProcInit(QStringLiteral("ps"), {QStringLiteral("aux")});
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &DBAdministration::onPsauxStopFinished);
|
||||
m_proc->start();
|
||||
}
|
||||
|
||||
void DBAdministration::onPsauxStopFinished()
|
||||
{
|
||||
enableButtons();
|
||||
QByteArray output = m_proc->readAllStandardOutput();
|
||||
|
||||
if (output.contains("svcServiceManagement"))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "ServiceManagement started - stopping";
|
||||
|
||||
handleProcInit(QCoreApplication::applicationDirPath() + QStringLiteral("/svcServiceManagement"), {QStringLiteral("-s")});
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &DBAdministration::onStopAppFinished);
|
||||
m_proc->start();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Service Management"), tr("Service Management already stopped."), QMessageBox::Ok);
|
||||
ERROR_LOG(m_logger) << "ServiceManagement already stopped";
|
||||
}
|
||||
}
|
||||
|
||||
void DBAdministration::onStopAppFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
handleProcFinished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void DBAdministration::onCopyDbFailed()
|
||||
{
|
||||
QMessageBox::critical(this, tr ("Exercise"), tr("Could not copy exercise - maybe the exercise already exists."), QMessageBox::Ok);
|
||||
enableButtons();
|
||||
m_progressDialog->hide();
|
||||
}
|
||||
|
||||
void DBAdministration::onCopyDbFinished()
|
||||
{
|
||||
m_localDatabasesModel->initModel(m_copyExercise->evaluationDb());
|
||||
m_ui->tableViewLocalDatabases->resizeColumnsToContents();
|
||||
enableButtons();
|
||||
m_progressDialog->hide();
|
||||
}
|
||||
|
||||
|
||||
void DBAdministration::handleProcInit(const QString &program, const QStringList &args)
|
||||
{
|
||||
if (m_proc)
|
||||
{
|
||||
m_proc->disconnect(this);
|
||||
m_proc->deleteLater();
|
||||
}
|
||||
m_proc = new QProcess(this);
|
||||
NOTICE_LOG(m_logger) << "Starting process '" << program << "' with args '"
|
||||
<< args.join(QLatin1Char(' ')) << "'";
|
||||
|
||||
m_proc->setProgram(program);
|
||||
m_proc->setArguments(args);
|
||||
connect(m_proc, &QProcess::errorOccurred,
|
||||
this, &DBAdministration::onErrorOccured);
|
||||
disableButtons();
|
||||
}
|
||||
|
||||
void DBAdministration::handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
enableButtons();
|
||||
|
||||
if (!m_proc)
|
||||
return;
|
||||
if (exitCode != 0 || exitStatus != 0)
|
||||
{
|
||||
QByteArray out = m_proc->readAllStandardError();
|
||||
if (!out.isEmpty())
|
||||
out += '\n';
|
||||
out += m_proc->readAllStandardOutput();
|
||||
ERROR_LOG(m_logger) << "Process finished - exitCode: " << exitCode << ", exitStatus = " << exitStatus << ", " << out;
|
||||
QMessageBox::critical(this,
|
||||
tr ("Execute process"), tr("Error executing process, exitCode: %1, exitStatus: %2, output: %3")
|
||||
.arg(exitCode).arg(exitStatus).arg(QString::fromLocal8Bit(out)),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
m_proc->disconnect(this);
|
||||
m_proc->deleteLater();
|
||||
m_proc = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void DBAdministration::enaDisaButtons(bool bEnable)
|
||||
{
|
||||
{
|
||||
const QList<QPushButton*> l = findChildren<QPushButton*>();
|
||||
for (QPushButton *pb : l)
|
||||
pb->setEnabled(bEnable);
|
||||
}
|
||||
{
|
||||
const QList<QAction*> l = findChildren<QAction*>();
|
||||
for (QAction *a : l)
|
||||
a->setEnabled(bEnable);
|
||||
}
|
||||
if (bEnable)
|
||||
enaDisa();
|
||||
}
|
||||
|
||||
bool DBAdministration::checkRunsOnEvaluationServer() const
|
||||
{
|
||||
const QHostInfo hostInfoEvaluationDb = QHostInfo::fromName(Settings::evaluationDatabaseHost());
|
||||
const auto evaluationDbAddresses = hostInfoEvaluationDb.addresses();
|
||||
if (hostInfoEvaluationDb.addresses().isEmpty())
|
||||
return false; // we don't know better ...
|
||||
|
||||
const QList<QHostAddress> addresses = QNetworkInterface::allAddresses();
|
||||
for (const QHostAddress &address : addresses)
|
||||
{
|
||||
if (address.isLoopback() || address.isNull())
|
||||
continue;
|
||||
if (address.protocol() != QAbstractSocket::IPv4Protocol)
|
||||
continue;
|
||||
for (const QHostAddress &evaluationAddress : evaluationDbAddresses)
|
||||
if (address.isEqual(evaluationAddress))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace DBAdministration
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* @RDE_HEADER@
|
||||
* <short description>
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Malte Schröder, SLSE, 2016-06-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QMap>
|
||||
#include <QStandardItemModel>
|
||||
#include <QVector>
|
||||
#include <QCloseEvent>
|
||||
#include <QProcess>
|
||||
#include <QProgressDialog>
|
||||
#include <QMenuBar>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
#include "logger.h"
|
||||
#include "server_databases_model.h"
|
||||
#include "local_databases_model.h"
|
||||
#include "showLogFile.h"
|
||||
#include "copy_exercise.h"
|
||||
|
||||
namespace Ui {
|
||||
class DBAdministration;
|
||||
}
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
class DBAdministration : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DBAdministration(QWidget *parent = nullptr);
|
||||
~DBAdministration();
|
||||
|
||||
bool init();
|
||||
|
||||
private slots:
|
||||
void onClosedClicked();
|
||||
void onRemoveClicked();
|
||||
void onActivateClicked();
|
||||
void onCopyButtonClicked();
|
||||
void onDropDbFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onErrorOccured(QProcess::ProcessError error);
|
||||
void incrementProgressBar();
|
||||
void onShowLogFile();
|
||||
void onStartApp();
|
||||
void onStopApp();
|
||||
void onPsauxFinished();
|
||||
void onStartAppFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onPsauxStopFinished();
|
||||
void onStopAppFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onCopyDbFailed();
|
||||
void onCopyDbFinished();
|
||||
private:
|
||||
void enaDisa();
|
||||
void handleProcInit(const QString &program, const QStringList &args);
|
||||
void handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void disableButtons() { enaDisaButtons(false); }
|
||||
void enableButtons() { enaDisaButtons(true); }
|
||||
void enaDisaButtons(bool bEnable);
|
||||
bool checkRunsOnEvaluationServer() const;
|
||||
|
||||
private:
|
||||
Ui::DBAdministration *m_ui;
|
||||
ServerDatabasesModel *m_serverDatabasesModel;
|
||||
LocalDatabasesModel *m_localDatabasesModel;
|
||||
ServerDatabasesProxyModel *m_proxyModelServer;
|
||||
LocalDatabasesProxyModel *m_proxyModelLocal;
|
||||
QProcess *m_proc;
|
||||
QProgressDialog *m_progressDialog;
|
||||
QTimer *m_timer;
|
||||
QMenuBar *m_menuBar;
|
||||
ShowLogFile *m_showLog;
|
||||
LocalExercise m_localDatabaseToRemove;
|
||||
CopyExercise *m_copyExercise;
|
||||
bool m_bRunsOnEvaluationServer;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
} // namespace DBAdministration
|
||||
+791
@@ -0,0 +1,791 @@
|
||||
/**
|
||||
* EXM Database Administartion (Create Schema/Tables/Views etc)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-09-15
|
||||
*/
|
||||
|
||||
#include "exercise_table_generator.h"
|
||||
|
||||
#include <ngldb/nsqlquery.h>
|
||||
#include <ngldb/dbtransaction.h>
|
||||
|
||||
#include <QVariant>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QFile>
|
||||
#include <QSqlError>
|
||||
#include <QTextStream>
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
ExerciseTableGenerator::ExerciseTableGenerator(NGL::INGLLogger &logger, const QString &xmlPath, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_xmlPath(xmlPath)
|
||||
, m_ownSchemaName(QLatin1String("exm"))
|
||||
, m_logger(logger)
|
||||
{
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
ExerciseTableGenerator::~ExerciseTableGenerator()
|
||||
{
|
||||
qDeleteAll(m_sqlGeneratorMap);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::existsSchema(const QString &dbSchema, const QSqlDatabase &dbConn) const
|
||||
{
|
||||
NSqlQuery q(dbConn);
|
||||
|
||||
// Does service schema exist?
|
||||
QString stmt = QLatin1String("SELECT EXISTS(SELECT 1 FROM information_schema.schemata") +
|
||||
QLatin1String(" WHERE schema_name = '") + dbSchema + QLatin1String("')");
|
||||
|
||||
if (!q.execAndFetch(stmt))
|
||||
return false;
|
||||
|
||||
return q.value(0).toBool();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
//bool ExerciseTableGenerator::createDbSchemaIfNotExists(const QString &dbSchema) const
|
||||
//{
|
||||
// // TODO: make product-dependent
|
||||
// QString dbUser = QLatin1String("ets_") + dbSchema;
|
||||
// return createDbSchemaIfNotExists(dbSchema, dbUser);
|
||||
//}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::createDbSchemaIfNotExists(const QString &dbSchema, QString dbUser) const
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "createDbSchema: dbSchema = " << dbSchema << ", dbUser = " << dbUser;
|
||||
if (existsSchema(dbSchema, m_database))
|
||||
return true;
|
||||
|
||||
// Schema doesn't exist => create
|
||||
QString stmt = QLatin1String("CREATE SCHEMA IF NOT EXISTS ") + dbSchema;
|
||||
DEBUG_LOG(m_logger) << "# " << stmt;
|
||||
|
||||
NSqlQuery q(m_database);
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can't create schema '" << dbSchema << "' : " << q.getLastSqlError();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create specific user for schema (if exercise-related)
|
||||
if (dbSchema.startsWith(QLatin1String("ex_")))
|
||||
{
|
||||
dbUser = QStringLiteral("ets_ex_00");
|
||||
stmt = QLatin1String("SELECT create_user_if_not_exists('") + dbUser + QLatin1String("');");
|
||||
DEBUG_LOG(m_logger) << "# " << stmt;
|
||||
// Use stored procedure (=> create user only if not exists)
|
||||
if (!q.exec(stmt))
|
||||
return false;
|
||||
|
||||
// Add user to group <product>_ro: not needed anymore, it is included in stored procedure
|
||||
// stmt = QLatin1String(" GRANT ets_ro TO ") + dbUser;
|
||||
// DEBUG_LOG(m_logger) << "# " << stmt;
|
||||
// if (!q.exec(stmt))
|
||||
// return false;
|
||||
|
||||
}
|
||||
|
||||
// TODO: make dba user & db groups depend on product => Check/product Name needed somewhere: lts-cc.conf?
|
||||
// HR: 09.03.2016
|
||||
stmt = QLatin1String("GRANT USAGE ON SCHEMA ") + dbSchema +
|
||||
QLatin1String(" TO ets_ro, ets_admin");
|
||||
|
||||
DEBUG_LOG(m_logger) << "# " << stmt;
|
||||
if (!q.exec(stmt))
|
||||
return false;
|
||||
|
||||
// create db_version table needed later for DB Updates
|
||||
QString stmtDbVersion = QLatin1String("CREATE TABLE IF NOT EXISTS ") + dbSchema + QLatin1String(".db_version (")+
|
||||
QLatin1String("id serial, ")+
|
||||
QLatin1String("description text, ")+
|
||||
QLatin1String("version text, ")+
|
||||
QLatin1String("updated bigint DEFAULT (extract(epoch from now()) * 1000), ")+
|
||||
QLatin1String("success boolean DEFAULT true, ")+
|
||||
QLatin1String("message text);");
|
||||
stmtDbVersion += QLatin1String("\nINSERT INTO ") + dbSchema + QLatin1String(".db_version (description, version) VALUES ('Create db_version table for all existent DB schemas', '1.00')");
|
||||
if (!q.exec(stmtDbVersion))
|
||||
WARNING_LOG(m_logger) << "DB: Could not create db_version table for schema " << dbSchema << "! Error code: " << q.lastError().nativeErrorCode();
|
||||
else
|
||||
INFO_LOG(m_logger) << "DB: created db_version table for schema " << dbSchema;
|
||||
|
||||
INFO_LOG(m_logger) << "########## DbSchema " << dbSchema << " created with corresponding rights.";
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::dropDbSchema(const QString &dbSchema, const QString &dbUser) const
|
||||
{
|
||||
// Drop Schema
|
||||
QString stmt = QLatin1String("DROP SCHEMA IF EXISTS ") + dbSchema + QLatin1String(" CASCADE");
|
||||
DEBUG_LOG(m_logger) << "# " << stmt;
|
||||
|
||||
NSqlQuery q(m_database);
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can't drop schema '" << dbSchema << "' : " << q.getLastSqlError();
|
||||
return false;
|
||||
}
|
||||
|
||||
// drop only "old" users: ets_ex_42 etc
|
||||
if (!dbUser.isEmpty() && dbUser != QStringLiteral("ets_ex_00"))
|
||||
{
|
||||
// Drop related user
|
||||
stmt = QLatin1String("DROP USER ") + dbUser;
|
||||
if (!q.exec(stmt))
|
||||
WARNING_LOG(m_logger) << "Can't drop user '" << dbUser << "' : " << q.getLastSqlError();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if table exists / is available for dbUser
|
||||
* (dbUser has the right to see it)
|
||||
* @param tableName
|
||||
* @param dbSchema
|
||||
* @return true on success
|
||||
*/
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::existsTable(const QString &tableName, const QString &dbSchema) const
|
||||
{
|
||||
QString stmt = QLatin1String("SELECT EXISTS ("
|
||||
" SELECT 1 FROM information_schema.tables "
|
||||
" WHERE table_schema = '") + dbSchema + QLatin1String("'"
|
||||
" AND table_name = '") + tableName + QLatin1String("')");
|
||||
|
||||
DEBUG_LOG(m_logger) << "stmt: " << stmt;
|
||||
NSqlQuery q(m_database);
|
||||
|
||||
if (!q.execAndFetch(stmt))
|
||||
{
|
||||
INFO_LOG(m_logger) << "Table " << tableName << " does not exist in schema " << dbSchema;
|
||||
return false;
|
||||
}
|
||||
|
||||
return q.value(0).toBool();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ExerciseTableGenerator::init
|
||||
* @param createOwnSchema
|
||||
* @return
|
||||
*/
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::init(const QSqlDatabase &database, const QString &ownSchemaName, bool createOwnSchema)
|
||||
{
|
||||
m_database = database;
|
||||
m_ownSchemaName = ownSchemaName;
|
||||
if (!createOwnSchema && !existsSchema(m_ownSchemaName, m_database))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Schema of the service (" << m_ownSchemaName << ") doesn't exist, aborting." ;
|
||||
return false;
|
||||
}
|
||||
|
||||
resetSearchPath();
|
||||
|
||||
// Read all xmlFiles in xmlPath
|
||||
DEBUG_LOG(m_logger) << "xmlPath: " << m_xmlPath;
|
||||
QFileInfo fi(m_xmlPath);
|
||||
if (!fi.isDir())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Given xml path '" << m_xmlPath << "' is not a directory";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDir xmlDir(m_xmlPath);
|
||||
|
||||
// Read xmlFiles only
|
||||
QStringList filters;
|
||||
filters << QLatin1String("*.xml");
|
||||
xmlDir.setNameFilters(filters);
|
||||
|
||||
qDeleteAll(m_sqlGeneratorMap);
|
||||
m_sqlGeneratorMap.clear();
|
||||
QDirIterator dirIt(xmlDir);
|
||||
while (dirIt.hasNext())
|
||||
{
|
||||
const QString xmlFile = dirIt.next();
|
||||
DEBUG_LOG(m_logger) << "xmlFile: " << xmlFile;
|
||||
|
||||
// Init sqlGenerator for xmlFile
|
||||
CodeGen::SqlGenerator *sqlGen = new CodeGen::SqlGenerator(xmlFile);
|
||||
if (sqlGen->generateData(0) && sqlGen->isValid())
|
||||
m_sqlGeneratorMap.insert(sqlGen->getServiceAbbr(), sqlGen);
|
||||
else
|
||||
delete sqlGen;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "sqlGen mapSize: " << m_sqlGeneratorMap.size();
|
||||
|
||||
emit aliveSignal();
|
||||
|
||||
if (createOwnSchema)
|
||||
{
|
||||
// Create Schema exm (i.e. for testing)
|
||||
// TODO: make product-dependent
|
||||
QString dbUser = QLatin1String("ets_exm");
|
||||
|
||||
if (!createDbSchemaIfNotExists(m_ownSchemaName, dbUser))
|
||||
return false;
|
||||
|
||||
if (!executeSqlTableRelated(QStringLiteral("exm"), m_ownSchemaName, dbUser))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExerciseTableGenerator::close()
|
||||
{
|
||||
m_database = QSqlDatabase();
|
||||
}
|
||||
|
||||
// Write sql-stmts for a service into a file
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::writeServiceSqlToFile(const QString &svcName, const QString &dbSchema)
|
||||
{
|
||||
if (!m_sqlGeneratorMap.contains(svcName))
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Write sql for service '" << svcName
|
||||
<< "' with schema '" << dbSchema << "'";
|
||||
|
||||
CodeGen::SqlGenerator *sqlGen = m_sqlGeneratorMap.value(svcName);
|
||||
// do not write to share/Lts/sql to not overwrite the generated files from codegen
|
||||
QString fullSqlName = QDir::tempPath() + QLatin1Char('/') + svcName + QLatin1Char('_') + dbSchema + QLatin1String(".sql");
|
||||
|
||||
if (!sqlGen->writeSqlToFile(dbSchema, fullSqlName, CodeGen::ExerciseDependency::Exercise))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Failed to write sql-stmt to file "
|
||||
<< fullSqlName;
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "## => Written sql-stmt to '" << fullSqlName << "'";
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::executeSql(const QString &svcName, const QString &dbSchema, QStringList &handledServices, const CodeGen::ExerciseDependency &ed)
|
||||
{
|
||||
// TODO: make product-dependent
|
||||
QString dbUser;
|
||||
if (dbSchema.startsWith(QLatin1String("ex_")))
|
||||
dbUser = QLatin1String("ets_ex_00");
|
||||
else
|
||||
dbUser = QLatin1String("ets_") + dbSchema;
|
||||
return executeSql(svcName, dbSchema, dbUser, handledServices, ed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Execute all sql-stmts for a service
|
||||
* @param svcName
|
||||
* @param dbSchema
|
||||
* @param dbUser
|
||||
* @return
|
||||
*/
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::executeSql(const QString &svcName, const QString &dbSchema, const QString &dbUser, QStringList &handledServices, const CodeGen::ExerciseDependency &ed)
|
||||
{
|
||||
CodeGen::SqlGenerator *sqlGen = m_sqlGeneratorMap.value(svcName);
|
||||
if (!sqlGen)
|
||||
return false;
|
||||
|
||||
// check if this service was already handled
|
||||
if (handledServices.contains(svcName))
|
||||
{
|
||||
INFO_LOG(m_logger) << "Service already in handledServices: " << svcName;
|
||||
return true;
|
||||
}
|
||||
handledServices += svcName;
|
||||
INFO_LOG(m_logger) << "Added service to handledServices: " << svcName;
|
||||
|
||||
//check if schema is empty at beginning, after executing some statements is not empty anymore
|
||||
// for exercise dependent services we execute all statements
|
||||
bool schemaEmpty = schemaIsEmpty(dbSchema) || ed == CodeGen::ExerciseDependency::Exercise;
|
||||
|
||||
// first execute all depedent services
|
||||
const auto deps = sqlGen->getReferencedServices();
|
||||
for (const QString &depSvc : deps)
|
||||
{
|
||||
if (!executeSql(depSvc, dbSchema, dbUser, handledServices, ed))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Failed to execute sql " << depSvc;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const QStringList stmts = sqlGen->getAllSqlStmts(dbSchema, ed);
|
||||
NSqlQuery q(m_database);
|
||||
int stmtExecuted = 0;
|
||||
|
||||
for (const QString &stmt : stmts)
|
||||
{
|
||||
if (stmt.isEmpty() || stmt.startsWith(QLatin1String("--")) || stmt.startsWith(QLatin1String("\n--")))
|
||||
continue;
|
||||
|
||||
if ((stmt.startsWith(QLatin1String("DROP TABLE")) || stmt.startsWith(QLatin1String("INSERT INTO"))) && !schemaEmpty)
|
||||
continue;
|
||||
|
||||
if ((stmt.startsWith(QLatin1String("DROP SEQUENCE")) || stmt.startsWith(QLatin1String("CREATE SEQUENCE"))) && !schemaEmpty)
|
||||
continue;
|
||||
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while executing stmt: '" << stmt << "' : " << q.getLastSqlError();
|
||||
return false;
|
||||
}
|
||||
checkAliveTimer();
|
||||
|
||||
NOTICE_LOG(m_logger) << "Statement executed: " << stmt;
|
||||
++stmtExecuted;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "#" << stmtExecuted << " stmts executed.";
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::schemaIsEmpty(const QString &dbSchema) const
|
||||
{
|
||||
NSqlQuery q(m_database);
|
||||
|
||||
QString stmt = QLatin1String("SELECT COUNT(*) FROM information_schema.tables") +
|
||||
QLatin1String(" WHERE table_schema = '") + dbSchema + QLatin1String("'");
|
||||
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
INFO_LOG(m_logger) << "Schema does not exist : " << dbSchema;
|
||||
return false;
|
||||
}
|
||||
|
||||
q.next();
|
||||
|
||||
if (q.value(0).toInt() > 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Execute only sql stmts for tables & table-related items (Sequences/PK/FK/Indexes)
|
||||
*
|
||||
* Note: sql stmts have an 'CREATE <> IF NOT EXISTS'
|
||||
* Additional check for tableExists necessary for inserting data
|
||||
* @param svcName
|
||||
* @param dbSchema
|
||||
* @param dbUser
|
||||
* @return
|
||||
*/
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::executeSqlTableRelated(const QString &svcName, const QString &dbSchema, const QString &dbUser)
|
||||
{
|
||||
if (!m_sqlGeneratorMap.contains(svcName))
|
||||
return false;
|
||||
|
||||
const CodeGen::SqlGenerator *sqlGen = m_sqlGeneratorMap.value(svcName);
|
||||
const CodeGen::SqlGenerator::SqlStatements sqlStatements = sqlGen->getStatements(CodeGen::ExerciseDependency::Global);
|
||||
const CodeGen::SqlGenerator::SqlItems sqlItems = sqlGen->getSqlItems(CodeGen::ExerciseDependency::Global);
|
||||
|
||||
// 1. Step: Check which tables will be created
|
||||
QStringList tablesNewlyCreated;
|
||||
for (const QString &tableName : sqlItems.tables)
|
||||
{
|
||||
if (!existsTable(tableName, dbSchema))
|
||||
tablesNewlyCreated += tableName;
|
||||
}
|
||||
|
||||
// 2. Step: Set db-environment (privileges/search path)
|
||||
INFO_LOG(m_logger) << "Create TABLES for dbSchema = " << dbSchema << ", dbUser = " << dbUser;
|
||||
QStringList sqlStmts = sqlGen->getDbSettings(dbSchema);
|
||||
|
||||
// 3. Step: execute stmts
|
||||
|
||||
// Note: create sequence if not exists in postgresql 9.5
|
||||
sqlStmts += sqlStatements.createTables;
|
||||
|
||||
if (!executeStmts(sqlStmts))
|
||||
return false;
|
||||
|
||||
INFO_LOG(m_logger) << " #" << tablesNewlyCreated.size() << " tables created. ";
|
||||
// Primary Keys
|
||||
if (!executsSqlConstraints(sqlItems.primaryKeys, sqlStatements.createPrimaryKeys, dbSchema))
|
||||
return false;
|
||||
|
||||
// TODO: Foreign Keys
|
||||
//if (!executsSqlConstraints(sqlGen->getForeignKeys(), sqlStatements.createForeignKeys, dbSchema))
|
||||
// return false;
|
||||
|
||||
// Indexes
|
||||
if (!executsSqlConstraints(sqlItems.constraints, sqlStatements.createConstraints, dbSchema))
|
||||
return false;
|
||||
|
||||
// 4. Step: Handle sequences separately
|
||||
sqlStmts = sqlStatements.createSequences;
|
||||
int listIndexStmts = 0;
|
||||
for (QString sequenceName : sqlItems.sequences)
|
||||
{
|
||||
// TODO: remove when using postgresql 9.5 feature create sequence if not exists
|
||||
sequenceName.remove(dbSchema + QLatin1Char('.'));
|
||||
QString stmt = QLatin1String("SELECT exists_sequence('") + sequenceName + QLatin1String("', '")
|
||||
+ dbSchema + QLatin1String("')");
|
||||
NSqlQuery q(m_database);
|
||||
if (!q.execAndFetch(stmt))
|
||||
return false;
|
||||
|
||||
// Sequence exists?
|
||||
if (!q.value(0).toBool())
|
||||
q.exec(sqlStmts.at(listIndexStmts));
|
||||
|
||||
listIndexStmts++;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
for (const QString &table : qAsConst(tablesNewlyCreated))
|
||||
{
|
||||
if (!insertTableData(table, dbSchema, sqlGen))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Failed to insert data for table " << dbSchema << "." << table;
|
||||
ok &= false;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::executsSqlConstraints(const QStringList &constraintList, const QStringList &sqlStmts,
|
||||
const QString &dbSchema)
|
||||
{
|
||||
int listIndexStmts = 0;
|
||||
int createdConstraints = 0;
|
||||
|
||||
for (const QString &constraintName : constraintList)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Check constraint '" << constraintName << "'";
|
||||
// TODO: remove when using postgresql 9.6 feature create constraint if not exists
|
||||
QString stmt = QLatin1String("SELECT exists_constraint('") + constraintName.toLower() + QLatin1String("', '")
|
||||
+ dbSchema + QLatin1String("', '") + QLatin1String("i')");
|
||||
|
||||
//DEBUG_LOG(m_logger) << "stmt = " << stmt;
|
||||
NSqlQuery q(m_database);
|
||||
if (!q.execAndFetch(stmt))
|
||||
return false;
|
||||
|
||||
// Constraint exists?
|
||||
if (!q.value(0).toBool())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Constraint '" << constraintName << "' does not exist, creating ..";
|
||||
if (!q.exec(sqlStmts.at(listIndexStmts)))
|
||||
return false;
|
||||
|
||||
createdConstraints++;
|
||||
}
|
||||
|
||||
listIndexStmts++;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << " #" << createdConstraints << " constraints created. ";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExerciseTableGenerator::checkAliveTimer()
|
||||
{
|
||||
if (m_emitAliveTimer.elapsed() > 2000) // longer than 2 sec -> send heartbeat
|
||||
{
|
||||
emit aliveSignal();
|
||||
m_emitAliveTimer.start();
|
||||
}
|
||||
}
|
||||
// (Re)Create sql statements for given exercise
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
void ExerciseTableGenerator::generateSqlDataForExercise(int exerciseId)
|
||||
{
|
||||
for (CodeGen::SqlGenerator *sqlGen : qAsConst(m_sqlGeneratorMap))
|
||||
{
|
||||
// recreate sql statement with correct schema name (e.g. for serials)
|
||||
if (!sqlGen->generateData(exerciseId))
|
||||
ERROR_LOG(m_logger) << "Error generating sql for exercise " << exerciseId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ExerciseTableGenerator::executeStmts
|
||||
* @param stmts
|
||||
* @return true on success
|
||||
*/
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::executeStmts(const QStringList &stmts)
|
||||
{
|
||||
NSqlQuery q(m_database);
|
||||
int stmtExecuted = 0;
|
||||
|
||||
for (const QString &stmt : stmts)
|
||||
{
|
||||
if (stmt.isEmpty() || stmt.startsWith(QLatin1String("--")) || stmt.startsWith(QLatin1String("\n--")))
|
||||
continue;
|
||||
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while executing stmt: '" << stmt << "' : " << q.getLastSqlError();
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Executed statement: " << stmt;
|
||||
++stmtExecuted;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "#" << stmtExecuted << " stmts executed.";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ExerciseTableGenerator::insertTableData
|
||||
* insert possible static data for newly created table
|
||||
* @param table
|
||||
* @param dbSchema
|
||||
* @return true on success
|
||||
*/
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::insertTableData(const QString &table, const QString &dbSchema, const CodeGen::SqlGenerator *sqlGen)
|
||||
{
|
||||
// inserts are only enumValues
|
||||
const QStringList &enumInserts = sqlGen->getEnumerationInsertValues(table, dbSchema);
|
||||
if (!executeStmts(enumInserts))
|
||||
return false;
|
||||
|
||||
INFO_LOG(m_logger) << " #" << enumInserts.count() << " rows inserted for " << dbSchema << "." << table;
|
||||
|
||||
// TODO: add other static data
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
// Write sql-stmts to a file for a specific exercise
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::writeExerciseServicesSql(qint32 exerciseId)
|
||||
{
|
||||
bool ok = false;
|
||||
QString schemaName = DBCommon::getExerciseSchemaName(exerciseId);
|
||||
|
||||
for (auto it = m_sqlGeneratorMap.constBegin(); it != m_sqlGeneratorMap.constEnd(); ++it)
|
||||
{
|
||||
if (!it.value()->isServiceExerciseIndependent())
|
||||
ok &= writeServiceSqlToFile(it.key(), schemaName);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief getAvailableExerciseServices
|
||||
* @return
|
||||
*/
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
QStringList ExerciseTableGenerator::getAvailableExerciseServices() const
|
||||
{
|
||||
QStringList services;
|
||||
for (auto it = m_sqlGeneratorMap.constBegin(); it != m_sqlGeneratorMap.constEnd(); ++it)
|
||||
{
|
||||
if (!it.value()->isServiceExerciseIndependent())
|
||||
services.append(it.key());
|
||||
}
|
||||
return services;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
QStringList ExerciseTableGenerator::getAvailableGlobalServices() const
|
||||
{
|
||||
QStringList services;
|
||||
for (auto it = m_sqlGeneratorMap.constBegin(); it != m_sqlGeneratorMap.constEnd(); ++it)
|
||||
{
|
||||
// if (it.value()->isServiceExerciseIndependent() || it.value()->getExerciseDependency() == CodeGen::ExerciseDependency::GlobalAndExercise)
|
||||
if (it.value()->isServiceGlobal())
|
||||
{
|
||||
services.append(it.key());
|
||||
DEBUG_LOG(m_logger) << "Global service found: " << it.key();
|
||||
}
|
||||
}
|
||||
return services;
|
||||
}
|
||||
|
||||
// Execute sql-stmts for a specific exercise (for all exercise-depended services)
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::executeSql(qint32 exerciseId)
|
||||
{
|
||||
const QStringList services = getAvailableExerciseServices();
|
||||
|
||||
// Define schema for given exerciseId
|
||||
QString schemaName = DBCommon::getExerciseSchemaName(exerciseId);
|
||||
DEBUG_LOG(m_logger) << "Create schema for EXERCISE " << schemaName;
|
||||
|
||||
generateSqlDataForExercise(exerciseId);
|
||||
|
||||
m_emitAliveTimer.start();
|
||||
|
||||
// Create dbSchema & tables, .. in a transaction
|
||||
// => can be reverted if an error occured
|
||||
DBTransaction trans(m_database);
|
||||
QStringList handledServices;
|
||||
for (const QString &svcName : services)
|
||||
{
|
||||
CodeGen::SqlGenerator *sqlGen = m_sqlGeneratorMap.value(svcName);
|
||||
if (!sqlGen)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can not find sqlgen for service " << svcName
|
||||
<< " - Skipping!";
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "-----------------------------------------------------------------------------";
|
||||
DEBUG_LOG(m_logger) << "Create exercise dependent tables/views/indexes/.. for service '" << svcName << "', exercise: " << exerciseId;
|
||||
if (!executeSql(svcName, schemaName, handledServices, CodeGen::ExerciseDependency::Exercise))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Failed to create db-environment (tables/views/indexes/..) for service '" << svcName << "'";
|
||||
trans.rollback();
|
||||
return false;
|
||||
}
|
||||
checkAliveTimer();
|
||||
|
||||
QFile predefinedSql;
|
||||
QString filePath = m_xmlPath;
|
||||
filePath.replace(QLatin1String("xml"), QLatin1String("sql"));
|
||||
DEBUG_LOG(m_logger) << "File Path: " << filePath;
|
||||
predefinedSql.setFileName(filePath + svcName + QLatin1String("_predefined_data.sql"));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Predefined filename " << predefinedSql.fileName();
|
||||
|
||||
if (predefinedSql.exists())
|
||||
{
|
||||
if (!predefinedSql.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
return false;
|
||||
|
||||
QStringList predefinedInserts;
|
||||
QTextStream textStream(&predefinedSql);
|
||||
|
||||
while (!textStream.atEnd())
|
||||
{
|
||||
QString line = textStream.readLine();
|
||||
line = line.replace(QStringLiteral("%ex_id%"), QString::number(exerciseId));
|
||||
DEBUG_LOG(m_logger) << "Line: " << line;
|
||||
predefinedInserts << line;
|
||||
}
|
||||
|
||||
predefinedSql.close();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Executing predefined statements: \n" << predefinedInserts.join(QStringLiteral("\n"));
|
||||
|
||||
if (!executeStmts(predefinedInserts))
|
||||
return false;
|
||||
|
||||
checkAliveTimer();
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "db-environment (tables/views/indexes/..) created for service '" << svcName << "'";
|
||||
}
|
||||
|
||||
// Commit all dbChanges
|
||||
trans.commit();
|
||||
|
||||
resetSearchPath();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Execute sql-stmts for all exercise-independent services
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::executeSql()
|
||||
{
|
||||
const QStringList services = getAvailableGlobalServices();
|
||||
DEBUG_LOG(m_logger) << "Found global services :" << services.size() ;
|
||||
|
||||
// Create dbSchema & tables, .. in a transaction
|
||||
// => can be reverted if an error occured
|
||||
DBTransaction trans(m_database);
|
||||
QStringList handledServices;
|
||||
NSqlQuery querySchemaExists(m_database);
|
||||
// querySchemaExists.prepare(QStringLiteral("SELECT count(*) FROM information_schema.schemata where schema_name = :sn"));
|
||||
querySchemaExists.prepare(QStringLiteral("SELECT count(*) FROM information_schema.tables where table_schema = :sn"));
|
||||
for (const QString &svc : services)
|
||||
{
|
||||
// we should not recreate already existing schemas since this will destroy FKs from ex_N.foo.bar_id to <global>.bar.id
|
||||
querySchemaExists.bindValue(QStringLiteral(":sn"), svc);
|
||||
if (querySchemaExists.execAndFetch())
|
||||
{
|
||||
const int num = querySchemaExists.value(0).toInt();
|
||||
if (num > 0)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Schema " << svc << " already exists - skip creating tables for this service";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "-------------------------------------------------------------------------------";
|
||||
DEBUG_LOG(m_logger) << "Create exercise independent tables/views/indexes/.. for service '" << svc << "'";
|
||||
if (!executeSql(svc, svc, handledServices, CodeGen::ExerciseDependency::Global))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Failed to create db-environment (tables/views/indexes/..) for service '" << svc << "'";
|
||||
trans.rollback();
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "db-environment (tables/views/indexes/..) created for service '" << svc << "'";
|
||||
}
|
||||
|
||||
// Commit all dbChanges
|
||||
trans.commit();
|
||||
|
||||
resetSearchPath();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Convenience functions
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::createExerciseSchema(qint32 exerciseId)
|
||||
{
|
||||
// Define schema for given exerciseId
|
||||
QString dbSchema = DBCommon::getExerciseSchemaName(exerciseId);
|
||||
QString dbUser = QLatin1String("ets_ex_00");
|
||||
return createDbSchemaIfNotExists(dbSchema, dbUser);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::dropExerciseSchema(qint32 exerciseId, bool bDropUser)
|
||||
{
|
||||
// Define schema for given exerciseId
|
||||
QString dbSchema = DBCommon::getExerciseSchemaName(exerciseId);
|
||||
|
||||
// TODO: make product-depended
|
||||
return dropDbSchema(dbSchema, bDropUser ? QLatin1String("ets_") + dbSchema : QString());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::resetSearchPath() const
|
||||
{
|
||||
// Reset of SEARCH_PATH (has changed in the process of creating a db)
|
||||
NSqlQuery q(m_database);
|
||||
QString stmt = QLatin1String("SET SEARCH_PATH TO ") + m_ownSchemaName + QLatin1String(", PUBLIC");
|
||||
return q.exec(stmt);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
bool ExerciseTableGenerator::isServiceGlobal(const QString &svcAbbr) const
|
||||
{
|
||||
CodeGen::SqlGenerator *sqlGen = m_sqlGeneratorMap.value(svcAbbr);
|
||||
if (!sqlGen)
|
||||
return false;
|
||||
|
||||
return sqlGen->isServiceGlobal();
|
||||
}
|
||||
|
||||
} // namespace DBAdministration
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* EXM Database Administartion (Create Schema/Tables/Views etc)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-09-15
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
#include <CodeGen/SqlGenerator.h>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
class SqlGenerator;
|
||||
}
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
|
||||
class ExerciseTableGenerator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ExerciseTableGenerator(NGL::INGLLogger &logger, const QString &xmlPath, QObject *parent = nullptr);
|
||||
virtual ~ExerciseTableGenerator();
|
||||
|
||||
bool init(const QSqlDatabase &database, const QString &ownSchemaName, bool createOwnSchema = false);
|
||||
void close();
|
||||
QStringList getAvailableServices() const { return m_sqlGeneratorMap.keys(); }
|
||||
bool isServiceGlobal(const QString &svcAbbr) const;
|
||||
|
||||
// Write sql-stmt for a service into a file
|
||||
bool writeServiceSqlToFile(const QString &svcName, const QString &dbSchema);
|
||||
bool executeSql(const QString &svcName, const QString &dbSchema, QStringList &handledServices, const CodeGen::ExerciseDependency &ed);
|
||||
bool executeSql(const QString &svcName, const QString &dbSchema, const QString &dbUser, QStringList &handledServices, const CodeGen::ExerciseDependency &ed);
|
||||
|
||||
// TODO: better naming
|
||||
bool executeSqlTableRelated(const QString &svcName, const QString &dbSchema, const QString &dbUser);
|
||||
|
||||
bool existsSchema(const QString &dbSchema, const QSqlDatabase &dbConn) const;
|
||||
//bool createDbSchemaIfNotExists(const QString &dbSchema) const;
|
||||
bool createDbSchemaIfNotExists(const QString &dbSchema, QString dbUser) const;
|
||||
bool dropDbSchema(const QString &dbSchema, const QString &dbUser) const;
|
||||
|
||||
bool existsTable(const QString &tableName, const QString &dbSchema) const;
|
||||
|
||||
bool insertTableData(const QString &table, const QString &dbSchema, const CodeGen::SqlGenerator *sqlGen );
|
||||
bool executeSql();
|
||||
|
||||
// Methods for a specific exercise
|
||||
bool writeExerciseServicesSql(qint32 exerciseId);
|
||||
bool executeSql(qint32 exerciseId);
|
||||
bool createExerciseSchema(qint32 exerciseId);
|
||||
bool dropExerciseSchema(qint32 exerciseId, bool bDropUser);
|
||||
QStringList getAvailableExerciseServices() const;
|
||||
QStringList getAvailableGlobalServices() const;
|
||||
|
||||
bool resetSearchPath() const;
|
||||
bool schemaIsEmpty(const QString &dbSchema) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void aliveSignal();
|
||||
protected:
|
||||
|
||||
void generateSqlDataForExercise(int exerciseId);
|
||||
bool executeStmts(const QStringList &stmts);
|
||||
bool executsSqlConstraints(const QStringList &constraintList,
|
||||
const QStringList &sqlStmts,
|
||||
const QString &dbSchema);
|
||||
|
||||
void checkAliveTimer();
|
||||
|
||||
private:
|
||||
// QMap<svcAbbr,Pointer SqlGenerator>
|
||||
QMap<QString,CodeGen::SqlGenerator*> m_sqlGeneratorMap;
|
||||
QString m_xmlPath;
|
||||
QString m_ownSchemaName;
|
||||
QSqlDatabase m_database;
|
||||
QElapsedTimer m_emitAliveTimer;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
} // namespace DBAdministration
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* PresentationManangement - Script Overview Dialog Model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-15
|
||||
*/
|
||||
|
||||
#include "local_databases_model.h"
|
||||
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QPalette>
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
|
||||
LocalDatabasesModel::LocalDatabasesModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_logger(getLogger("LocalDatabasesModel"))
|
||||
{}
|
||||
|
||||
|
||||
LocalDatabasesModel::~LocalDatabasesModel()
|
||||
{}
|
||||
|
||||
|
||||
bool LocalDatabasesModel::initModel(const QSqlDatabase &db)
|
||||
{
|
||||
beginResetModel();
|
||||
m_vecData.clear();
|
||||
endResetModel();
|
||||
|
||||
NSqlQuery q(db);
|
||||
|
||||
QString stmt = QStringLiteral("SELECT id, name, db_name, begin_time, end_time FROM local_databases");
|
||||
|
||||
if (!q.exec(stmt))
|
||||
return false;
|
||||
|
||||
while (q.next())
|
||||
{
|
||||
LocalExercise e;
|
||||
e.id = q.value(0).toInt();
|
||||
e.name = q.value(1).toString();
|
||||
e.dbName = q.value(2).toString();
|
||||
e.startTime = q.value(3).toLongLong();
|
||||
e.endTime = q.value(4).toLongLong();
|
||||
insertRow(e);
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "initModel - #exercises: " << m_vecData.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QVariant LocalDatabasesModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole || !index.isValid() || index.row() >= m_vecData.size())
|
||||
return QVariant();
|
||||
|
||||
const LocalExercise &e = m_vecData.at(index.row());
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case Id:
|
||||
return e.id;
|
||||
case Name:
|
||||
return QString(e.name);
|
||||
case DbName:
|
||||
return QString(e.dbName);
|
||||
case StartTime:
|
||||
return DTG::toStringMSec(e.startTime);
|
||||
case EndTime:
|
||||
return DTG::toStringMSec(e.endTime);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int LocalDatabasesModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : m_vecData.size();
|
||||
}
|
||||
|
||||
int LocalDatabasesModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : EndTime + 1;
|
||||
}
|
||||
|
||||
QVariant LocalDatabasesModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal
|
||||
&& role == Qt::DisplayRole)
|
||||
{
|
||||
Columns col = static_cast<Columns>(section);
|
||||
switch (col)
|
||||
{
|
||||
case Id:
|
||||
return tr("Id");
|
||||
case Name:
|
||||
return tr("Name");
|
||||
case DbName:
|
||||
return tr("Database Name");
|
||||
case StartTime:
|
||||
return tr("Start Time");
|
||||
case EndTime:
|
||||
return tr("End Time");
|
||||
}
|
||||
}
|
||||
return QAbstractTableModel::headerData(section, orientation, role);
|
||||
}
|
||||
|
||||
LocalExercise LocalDatabasesModel::getRowData(int row) const
|
||||
{
|
||||
if (row < 0 || row >= m_vecData.size())
|
||||
return LocalExercise();
|
||||
return m_vecData.at(row);
|
||||
}
|
||||
|
||||
bool LocalDatabasesModel::insertRow(const LocalExercise &item)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), m_vecData.size(), m_vecData.size());
|
||||
m_vecData.append(item);
|
||||
endInsertRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
void LocalDatabasesProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
|
||||
{
|
||||
m_sourceModel = qobject_cast<LocalDatabasesModel*>(sourceModel);
|
||||
QSortFilterProxyModel::setSourceModel(sourceModel);
|
||||
}
|
||||
|
||||
bool LocalDatabasesProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||||
{
|
||||
if (!m_sourceModel ||
|
||||
source_left.column() != source_right.column() ||
|
||||
!source_left.isValid() ||
|
||||
!source_right.isValid())
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
const auto &dataLeft = m_sourceModel->m_vecData.at(source_left.row());
|
||||
const auto dataRight = m_sourceModel->m_vecData.at(source_right.row());
|
||||
switch (source_left.column())
|
||||
{
|
||||
case LocalDatabasesModel::StartTime:
|
||||
return dataLeft.startTime < dataRight.startTime;
|
||||
case LocalDatabasesModel::EndTime:
|
||||
return dataLeft.endTime < dataRight.endTime;
|
||||
case LocalDatabasesModel::Id:
|
||||
case LocalDatabasesModel::Name:
|
||||
case LocalDatabasesModel::DbName:
|
||||
|
||||
break;
|
||||
}
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
|
||||
|
||||
} // namespace DBAdministration
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* PresentationManangement - Script Overview Dialog Model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-15
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class QSqlDatabase;
|
||||
namespace DBAdministration
|
||||
{
|
||||
|
||||
struct LocalExercise
|
||||
{
|
||||
qint32 id;
|
||||
QString name;
|
||||
QString dbName;
|
||||
qint64 startTime;
|
||||
qint64 endTime;
|
||||
};
|
||||
|
||||
class LocalDatabasesModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Columns
|
||||
{
|
||||
Id = 0,
|
||||
Name,
|
||||
DbName,
|
||||
StartTime,
|
||||
EndTime
|
||||
};
|
||||
|
||||
explicit LocalDatabasesModel(QObject *parent = nullptr);
|
||||
~LocalDatabasesModel();
|
||||
|
||||
bool initModel(const QSqlDatabase &db);
|
||||
|
||||
QVariant data(const QModelIndex &, int) const override final;
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override final;
|
||||
int columnCount(const QModelIndex &parent) const override final;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override final;
|
||||
LocalExercise getRowData(int row) const;
|
||||
bool insertRow(const LocalExercise &item);
|
||||
|
||||
friend class LocalDatabasesProxyModel;
|
||||
|
||||
private:
|
||||
QVector<LocalExercise> m_vecData;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
class LocalDatabasesProxyModel final : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using QSortFilterProxyModel::QSortFilterProxyModel;
|
||||
void setSourceModel(QAbstractItemModel *sourceModel) override;
|
||||
protected:
|
||||
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
|
||||
private:
|
||||
LocalDatabasesModel *m_sourceModel = nullptr;
|
||||
};
|
||||
}
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
log4j.reset=true
|
||||
log4j.rootLogger=WARN, file
|
||||
|
||||
# DbAdministration
|
||||
###########################################################
|
||||
|
||||
#log4j.logger.DbAdministration=DEBUG
|
||||
|
||||
# File
|
||||
###########################################################
|
||||
log4j.appender.file=Lts::RollingFileAppender
|
||||
log4j.appender.file.MaxFileSize=1MB
|
||||
log4j.appender.file.MaxBackupIndex=9
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Console
|
||||
###########################################################
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern= %d %p %c %c{1} - %m (%-.30F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Syslog
|
||||
###########################################################
|
||||
log4j.appender.syslog=org.apache.log4j.SyslogAppender
|
||||
log4j.appender.syslog.Threshold=ERROR
|
||||
log4j.appender.syslog.SysLogHost=localhost
|
||||
log4j.appender.syslog.Facility=LOCAL7
|
||||
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
|
||||
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
|
||||
|
||||
|
||||
###########################################################
|
||||
###########################################################
|
||||
###########################################################
|
||||
# 1) Available Levels in LOG4CXX Version 0.10.0:
|
||||
# TRACE,
|
||||
# DEBUG,
|
||||
# INFO,
|
||||
# WARN,
|
||||
# ERROR
|
||||
# FATAL
|
||||
#
|
||||
# d = date/time
|
||||
# p = priority (Level)
|
||||
# c = category/channel
|
||||
# m = message
|
||||
# F = file
|
||||
# L = line
|
||||
# n = platform dependent line separator character or characters.
|
||||
# ....
|
||||
#
|
||||
# Examples for console:
|
||||
# a)
|
||||
# %d %p %c #%m# (%.50F:%L)%n
|
||||
# date/time
|
||||
# priority
|
||||
# category/channel
|
||||
# #message#
|
||||
# (Maximal 50Character des Filename von rechts:Line)
|
||||
# line separator
|
||||
#
|
||||
# b)
|
||||
# %d (%.15F:%L) %-5p %c |#| %m%n
|
||||
# date/time
|
||||
# (Maximal 15Character des Filename von rechts:Line)
|
||||
# priority, Right pad with spaces if the priority name is less than 5 characters long.
|
||||
# category/channel
|
||||
# message
|
||||
# line separator
|
||||
#
|
||||
# Examples for files:
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Building Config - logging facility
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
|
||||
LOGGER_T getLogger(const char *name)
|
||||
{
|
||||
static const char ns[] = "DBA.";
|
||||
std::string loggerName;
|
||||
const size_t len = strlen(name);
|
||||
loggerName.reserve(sizeof(ns) + len);
|
||||
loggerName.append(ns, sizeof(ns) - 1);
|
||||
loggerName.append(name, len);
|
||||
|
||||
try
|
||||
{
|
||||
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
|
||||
getNGLLogger(loggerName);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
fprintf(stderr, "Error retrieving logger: %s", ex.what());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace DBAdministration
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Logging for Evaluations
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
typedef NGL::INGLLogger &LOGGER_T;
|
||||
|
||||
LOGGER_T getLogger(const char *name);
|
||||
inline LOGGER_T getLogger(const QString &loggerName)
|
||||
{
|
||||
return getLogger(loggerName.toUtf8().constData());
|
||||
}
|
||||
} // namespace DBAdministration
|
||||
Executable
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* @RDE_HEADER@
|
||||
* <short description>
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Malte Schröder, SLSE, 2016-06-08
|
||||
*/
|
||||
|
||||
#include "db_administration.h"
|
||||
#include "copy_exercise.h"
|
||||
#include "settings.h"
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <nglapplication/nglapplication.h>
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <ngltranslator/ngltranslator.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser(ProvideCommandLineParameterOptions::None)
|
||||
{
|
||||
addOption({{QStringLiteral("l"), QStringLiteral("lang")},
|
||||
QStringLiteral("Language iso code to use (de_DE, en_GB, en_US)"),
|
||||
QStringLiteral("<locale iso code>")
|
||||
});
|
||||
}
|
||||
QString langIsoCode() const { return value(QStringLiteral("l")); }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval = -1;
|
||||
bool bHeadless = false;
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (strcmp(argv[i], "-e") == 0)
|
||||
{
|
||||
bHeadless = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
QScopedPointer<QCoreApplication> app;
|
||||
app.reset(bHeadless ? dynamic_cast<QCoreApplication*>(new NGLCoreApplication(argc, argv))
|
||||
: dynamic_cast<QCoreApplication*>(new NGLApplication(argc, argv)));
|
||||
QCoreApplication::setApplicationName(QLatin1String("DBAdministration"));
|
||||
QCoreApplication::setOrganizationName(QLatin1String("RME"));
|
||||
|
||||
NGL::LoggerHandler *lh = dynamic_cast<NGL::LoggerHandler*>(app.data());
|
||||
lh->createLogger("DbAdministration", "log4cxx_dba.props");
|
||||
NGL::INGLLogger &logger = lh->baseLogger();
|
||||
|
||||
// Parse Options
|
||||
CmdLineParser options;
|
||||
if (!options.init())
|
||||
return retval;
|
||||
|
||||
// Set Translation
|
||||
QString langIsoCode = options.langIsoCode();
|
||||
if (langIsoCode.isEmpty())
|
||||
langIsoCode = QLocale::system().name();
|
||||
NGL::setTranslationLocale(langIsoCode.toLatin1());
|
||||
|
||||
DBAdministration::Settings::setIniFile(options.iniFile());
|
||||
|
||||
INFO_LOG(logger) << "ExerciseId: " << options.exerciseId();
|
||||
if (options.exerciseId() <= 0)
|
||||
{
|
||||
QScopedPointer<DBAdministration::DBAdministration> w(new DBAdministration::DBAdministration);
|
||||
if (!w->init())
|
||||
return -2;
|
||||
|
||||
STARTUP_LOG(logger);
|
||||
w->show();
|
||||
QGuiApplication::setQuitOnLastWindowClosed(true);
|
||||
retval = QCoreApplication::exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
DBAdministration::CopyExercise::CopyFor copyFor = DBAdministration::CopyExercise::CopyForEvaluation;
|
||||
QScopedPointer<DBAdministration::CopyExercise> w(new DBAdministration::CopyExercise(DBAdministration::getLogger("CopyExercise"), copyFor));
|
||||
if (!w->init(options.exerciseId(),
|
||||
DBAdministration::Settings::serverDatabaseHost(),
|
||||
DBAdministration::Settings::serverDatabaseName(),
|
||||
DBAdministration::Settings::evaluationDatabaseHost(),
|
||||
DBAdministration::Settings::evaluationDatabaseName()))
|
||||
return -2;
|
||||
|
||||
STARTUP_LOG(logger);
|
||||
if (!w->doCopy())
|
||||
return -3;
|
||||
|
||||
retval = QCoreApplication::exec();
|
||||
}
|
||||
SHUTDOWN_LOG(logger);
|
||||
|
||||
return retval;
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* PresentationManangement - Script Overview Dialog Model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-15
|
||||
*/
|
||||
|
||||
#include "server_databases_model.h"
|
||||
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QPalette>
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
|
||||
ServerDatabasesModel::ServerDatabasesModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_logger(getLogger("ServerDatabasesModel"))
|
||||
{}
|
||||
|
||||
|
||||
ServerDatabasesModel::~ServerDatabasesModel()
|
||||
{}
|
||||
|
||||
|
||||
bool ServerDatabasesModel::initModel(const QSqlDatabase &db)
|
||||
{
|
||||
beginResetModel();
|
||||
m_vecData.clear();
|
||||
endResetModel();
|
||||
|
||||
NSqlQuery q(db);
|
||||
|
||||
QString stmt = QStringLiteral("SELECT id, name, begin_time, end_time FROM exm.exercise");
|
||||
|
||||
if (!q.exec(stmt))
|
||||
return false;
|
||||
|
||||
while (q.next())
|
||||
{
|
||||
Exercise e;
|
||||
e.id = q.value(0).toInt();
|
||||
e.name = q.value(1).toString();
|
||||
e.startTime = q.value(2).toLongLong();
|
||||
e.endTime = q.value(3).toLongLong();
|
||||
insertRow(e);
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "initModel - #exercises: " << m_vecData.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QVariant ServerDatabasesModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole || !index.isValid() || index.row() >= m_vecData.size())
|
||||
return QVariant();
|
||||
|
||||
const Exercise &e = m_vecData.at(index.row());
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case Id:
|
||||
return e.id;
|
||||
case Name:
|
||||
return QString(e.name);
|
||||
case StartTime:
|
||||
return DTG::toStringMSec(e.startTime);
|
||||
case EndTime:
|
||||
return DTG::toStringMSec(e.endTime);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int ServerDatabasesModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : m_vecData.size();
|
||||
}
|
||||
|
||||
int ServerDatabasesModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : EndTime + 1;
|
||||
}
|
||||
|
||||
QVariant ServerDatabasesModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal
|
||||
&& role == Qt::DisplayRole)
|
||||
{
|
||||
Columns col = static_cast<Columns>(section);
|
||||
switch (col)
|
||||
{
|
||||
case Id:
|
||||
return tr("Id");
|
||||
case Name:
|
||||
return tr("Name");
|
||||
case StartTime:
|
||||
return tr("Start Time");
|
||||
case EndTime:
|
||||
return tr("End Time");
|
||||
}
|
||||
}
|
||||
return QAbstractTableModel::headerData(section, orientation, role);
|
||||
}
|
||||
|
||||
Exercise ServerDatabasesModel::getRowData(int row) const
|
||||
{
|
||||
if (row < 0 || row >= m_vecData.size())
|
||||
return Exercise();
|
||||
return m_vecData.at(row);
|
||||
}
|
||||
|
||||
bool ServerDatabasesModel::insertRow(const Exercise &item)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), m_vecData.size(), m_vecData.size());
|
||||
m_vecData.append(item);
|
||||
endInsertRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ServerDatabasesProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
|
||||
{
|
||||
m_sourceModel = qobject_cast<ServerDatabasesModel*>(sourceModel);
|
||||
QSortFilterProxyModel::setSourceModel(sourceModel);
|
||||
}
|
||||
|
||||
bool ServerDatabasesProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||||
{
|
||||
if (!m_sourceModel ||
|
||||
source_left.column() != source_right.column() ||
|
||||
!source_left.isValid() ||
|
||||
!source_right.isValid())
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
const auto &dataLeft = m_sourceModel->m_vecData.at(source_left.row());
|
||||
const auto dataRight = m_sourceModel->m_vecData.at(source_right.row());
|
||||
switch (source_left.column())
|
||||
{
|
||||
case ServerDatabasesModel::StartTime:
|
||||
return dataLeft.startTime < dataRight.startTime;
|
||||
case ServerDatabasesModel::EndTime:
|
||||
return dataLeft.endTime < dataRight.endTime;
|
||||
case ServerDatabasesModel::Id:
|
||||
case ServerDatabasesModel::Name:
|
||||
break;
|
||||
}
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
|
||||
|
||||
} // namespace DBAdministration
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* PresentationManangement - Script Overview Dialog Model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-15
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class QSqlDatabase;
|
||||
namespace DBAdministration
|
||||
{
|
||||
|
||||
struct Exercise
|
||||
{
|
||||
qint32 id = 0;
|
||||
QString name;
|
||||
qint64 startTime = 0;
|
||||
qint64 endTime = 0;
|
||||
};
|
||||
|
||||
class ServerDatabasesModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Columns
|
||||
{
|
||||
Id = 0,
|
||||
Name,
|
||||
StartTime,
|
||||
EndTime
|
||||
};
|
||||
|
||||
explicit ServerDatabasesModel(QObject *parent = nullptr);
|
||||
~ServerDatabasesModel();
|
||||
|
||||
bool initModel(const QSqlDatabase &db);
|
||||
|
||||
QVariant data(const QModelIndex &, int) const override final;
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override final;
|
||||
int columnCount(const QModelIndex &parent) const override final;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override final;
|
||||
Exercise getRowData(int row) const;
|
||||
bool insertRow(const Exercise &item);
|
||||
|
||||
friend class ServerDatabasesProxyModel;
|
||||
protected:
|
||||
|
||||
private:
|
||||
QVector<Exercise> m_vecData;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
class ServerDatabasesProxyModel final : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using QSortFilterProxyModel::QSortFilterProxyModel;
|
||||
void setSourceModel(QAbstractItemModel *sourceModel) override;
|
||||
protected:
|
||||
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
|
||||
private:
|
||||
ServerDatabasesModel *m_sourceModel = nullptr;
|
||||
};
|
||||
}
|
||||
Executable
+68
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Settings for CentralEffectSimulation
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QVariant>
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
class NGLSettingsClass : public NGL::Settings
|
||||
{
|
||||
public:
|
||||
NGLSettingsClass()
|
||||
: NGL::Settings(s_iniFile.isEmpty() ? NGL::findProjectConfigFile() : s_iniFile)
|
||||
{}
|
||||
static void setIniFile(const QString &fn)
|
||||
{
|
||||
s_iniFile = fn;
|
||||
}
|
||||
static QString s_iniFile;
|
||||
};
|
||||
QString NGLSettingsClass::s_iniFile;
|
||||
Q_GLOBAL_STATIC(NGLSettingsClass, s)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
NGL::Settings *Settings::settings()
|
||||
{
|
||||
return s();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Settings::setIniFile(const QString &ini)
|
||||
{
|
||||
NGLSettingsClass::setIniFile(ini);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QString Settings::serverDatabaseHost()
|
||||
{
|
||||
return s()->settings()->value(QStringLiteral("dbAdministration/DatabaseHostname"), QStringLiteral("EXCDBS01")).toString();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QString Settings::serverDatabaseName()
|
||||
{
|
||||
return s()->settings()->value(QStringLiteral("dbAdministration/DatabaseName"), QStringLiteral("lts_ets_pro")).toString();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QString Settings::evaluationDatabaseHost()
|
||||
{
|
||||
return s()->settings()->value(QStringLiteral("EvaluationDb/DatabaseHostname"), QStringLiteral("EXCADB01")).toString();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QString Settings::evaluationDatabaseName()
|
||||
{
|
||||
return s()->settings()->value(QStringLiteral("EvaluationDb/DatabaseName"), QStringLiteral("dbAdmin")).toString();
|
||||
}
|
||||
|
||||
|
||||
} // namespace DBAdministration
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Settings for CentralEffectSimulation
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QString>
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class Settings;
|
||||
}
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
namespace Settings
|
||||
{
|
||||
NGL::Settings *settings();
|
||||
void setIniFile(const QString &ini);
|
||||
QString serverDatabaseHost();
|
||||
QString serverDatabaseName();
|
||||
QString evaluationDatabaseHost();
|
||||
QString evaluationDatabaseName();
|
||||
}
|
||||
|
||||
} // namespace CentralEffectSimulation
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* @RDE_HEADER@
|
||||
* <short description>
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Malte Schröder, SLSE, 2016-06-08
|
||||
*/
|
||||
|
||||
#include "showLogFile.h"
|
||||
#include "ui_showLogFile.h"
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
ShowLogFile::ShowLogFile(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_ui(new Ui::ShowLogFile)
|
||||
, m_logger(getLogger("ShowLogFile"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
connect(m_ui->pbClose, &QPushButton::clicked, this, &ShowLogFile::onClosedClicked);
|
||||
|
||||
}
|
||||
|
||||
ShowLogFile::~ShowLogFile()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
bool ShowLogFile::init()
|
||||
{
|
||||
QString logFile = NGL::Settings::logPath() + QStringLiteral("/") + QString::fromLatin1(qgetenv("USER")) + QStringLiteral("_scm.log");
|
||||
|
||||
ERROR_LOG(m_logger) << "Logfile: " << logFile;
|
||||
|
||||
QFile file(logFile);
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Cannot open file " << logFile;
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray output = file.readAll();
|
||||
|
||||
m_ui->plainTextEdit->setPlainText(QString::fromLocal8Bit(output));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShowLogFile::onClosedClicked()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
} // namespace DBAdministration
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* @RDE_HEADER@
|
||||
* <short description>
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Malte Schröder, SLSE, 2016-06-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include "logger.h"
|
||||
|
||||
|
||||
namespace Ui {
|
||||
class ShowLogFile;
|
||||
}
|
||||
|
||||
namespace DBAdministration
|
||||
{
|
||||
class ShowLogFile : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ShowLogFile(QWidget *parent = nullptr);
|
||||
~ShowLogFile();
|
||||
|
||||
bool init();
|
||||
|
||||
private slots:
|
||||
void onClosedClicked();
|
||||
|
||||
private:
|
||||
Ui::ShowLogFile *m_ui;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DBAdministration</class>
|
||||
<widget class="QMainWindow" name="DBAdministration">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>846</width>
|
||||
<height>382</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Database administration</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonIconOnly</enum>
|
||||
</property>
|
||||
<property name="tabShape">
|
||||
<enum>QTabWidget::Rounded</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QTableView" name="tableViewServerDatabases">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="lblServerDatabases">
|
||||
<property name="text">
|
||||
<string>Server Databases:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="lblLocalDatabases">
|
||||
<property name="text">
|
||||
<string>Local Databases:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QTableView" name="tableViewLocalDatabases">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="pbCopy">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../Z/src/nglwidgets/nglresources.qrc">
|
||||
<normaloff>:/icons/16x16/go-next.png</normaloff>:/icons/16x16/go-next.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbActivate">
|
||||
<property name="text">
|
||||
<string>Activate Database</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbRemove">
|
||||
<property name="text">
|
||||
<string>Remove Database</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbClose">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>846</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuShow_Service_Management_Log_File">
|
||||
<property name="title">
|
||||
<string>&Logfile</string>
|
||||
</property>
|
||||
<addaction name="actionShow"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuService_Management">
|
||||
<property name="title">
|
||||
<string>Service &Management</string>
|
||||
</property>
|
||||
<addaction name="actionStart"/>
|
||||
<addaction name="actionStop"/>
|
||||
</widget>
|
||||
<addaction name="menuShow_Service_Management_Log_File"/>
|
||||
<addaction name="menuService_Management"/>
|
||||
</widget>
|
||||
<action name="actionShow">
|
||||
<property name="text">
|
||||
<string>&Show</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionStart">
|
||||
<property name="text">
|
||||
<string>&Start</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionStop">
|
||||
<property name="text">
|
||||
<string>St&op</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
<include location="../../../../Z/src/nglwidgets/nglresources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
<slots>
|
||||
<slot>oeffnenClicked()</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ShowLogFile</class>
|
||||
<widget class="QWidget" name="ShowLogFile">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>845</width>
|
||||
<height>532</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Show Logfile</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="plainTextEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="pbClose">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<slots>
|
||||
<slot>oeffnenClicked()</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
Reference in new issue
Block a user