Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
Executable
+919
@@ -0,0 +1,919 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* DBUpdate
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Iuliana Ojog, 2021-02-17
|
||||
*/
|
||||
|
||||
#include "db_update.h"
|
||||
#include "ui_db_update.h"
|
||||
#include "show_history.h"
|
||||
|
||||
#include <ngldb/dbconnection.h>
|
||||
#include <ngldb/dbtransaction.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QSqlError>
|
||||
|
||||
namespace DBUpdate
|
||||
{
|
||||
QString DBUpdate::m_defaultPath = QDir::homePath() + QStringLiteral("/bin/updates/");
|
||||
|
||||
DBUpdate::DBUpdate(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, m_ui(new Ui::DBUpdate)
|
||||
, m_showHistory(new ShowHistory)
|
||||
, m_logger(getLogger("DBUpdate"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
setWindowTitle(QLatin1String("Database Update"));
|
||||
|
||||
m_globalUpdatesModel = new GlobalUpdatesModel(this);
|
||||
m_globalUpdatesProxyModel = new GlobalUpdatesProxyModel(this);
|
||||
m_globalUpdatesProxyModel->setSourceModel(m_globalUpdatesModel);
|
||||
m_ui->tvGlobalUpdates->setModel(m_globalUpdatesProxyModel);
|
||||
connect(m_ui->tvGlobalUpdates, &QTableView::doubleClicked, this, &DBUpdate::onShowGlobalHistory);
|
||||
|
||||
m_exercisesModel = new ExercisesModel(this);
|
||||
m_exercisesProxyModel = new ExercisesProxyModel(this);
|
||||
m_exercisesProxyModel->setSourceModel(m_exercisesModel);
|
||||
m_ui->tvExerciseUpdates->setModel(m_exercisesProxyModel);
|
||||
connect(m_ui->tvExerciseUpdates, &QTableView::doubleClicked, this, &DBUpdate::onShowExerciseHistory);
|
||||
|
||||
connect(m_ui->tbClose, &QToolButton::clicked, this, &DBUpdate::onClosedClicked);
|
||||
connect(m_ui->tbLoadUpdate, &QToolButton::clicked, this, &DBUpdate::onUpdateLoad);
|
||||
connect(m_ui->tbRunUpdate, &QToolButton::clicked, this, &DBUpdate::onUpdateRun);
|
||||
connect(m_ui->tbShowLog, &QToolButton::clicked, this, &DBUpdate::onShowLogFile);
|
||||
connect(m_ui->tbClearLog, &QToolButton::clicked, this, &DBUpdate::onClearLogFile);
|
||||
connect(m_ui->tbLoadSQL, &QToolButton::clicked, this, &DBUpdate::onLoadSQL);
|
||||
connect(m_ui->tbBackup, &QToolButton::clicked, this, &DBUpdate::onBackupDB);
|
||||
|
||||
m_ui->tvExerciseUpdates->hideColumn(ExercisesModel::Columns::Id);
|
||||
m_ui->tvExerciseUpdates->hideColumn(ExercisesModel::Columns::StartTime);
|
||||
m_ui->tvExerciseUpdates->hideColumn(ExercisesModel::Columns::EndTime);
|
||||
//m_ui->tvExerciseUpdates->hideColumn(ExercisesModel::Columns::StateId);
|
||||
|
||||
enaDisa();
|
||||
}
|
||||
|
||||
DBUpdate::~DBUpdate()
|
||||
{
|
||||
delete m_showHistory;
|
||||
delete m_globalUpdatesModel;
|
||||
delete m_globalUpdatesProxyModel;
|
||||
delete m_exercisesModel;
|
||||
delete m_exercisesProxyModel;
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
bool DBUpdate::init()
|
||||
{
|
||||
QString str;
|
||||
NGL::Settings s(str);
|
||||
|
||||
// open postgres db, read table structure, read static data
|
||||
const QString dbUser(QStringLiteral("postgres"));
|
||||
const QString dbPasswd(QStringLiteral("postgres"));
|
||||
m_db = DBConnection::open(m_logger,
|
||||
dbUser,
|
||||
dbPasswd,
|
||||
s.databaseDriver(),
|
||||
s.databaseHostname(),
|
||||
s.databaseName());
|
||||
if (!m_db.isOpen())
|
||||
return false;
|
||||
|
||||
m_ui->lblDbConnection->setText(m_db.hostName() + QStringLiteral(" / ") + m_db.databaseName());
|
||||
enaDisa();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DBUpdate::onClosedClicked()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void DBUpdate::onUpdateLoad()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onUpdateLoad";
|
||||
|
||||
// open dialog
|
||||
const QStringList filter(
|
||||
{
|
||||
tr("Update Files (*.upd)"),
|
||||
#ifdef Q_OS_WIN
|
||||
tr("All (*.*)")
|
||||
#else
|
||||
tr("All (*)")
|
||||
#endif
|
||||
});
|
||||
|
||||
QString fileName = QFileDialog::getOpenFileName(this,
|
||||
tr("Load database update file"),
|
||||
m_defaultPath,
|
||||
filter.join(QStringLiteral(";;")));
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
QFileInfo fileInfo(fileName);
|
||||
if (!fileInfo.isReadable())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error!"), tr("An error occurred while loading the file.\n"
|
||||
"The loaded file is not readable."));
|
||||
return;
|
||||
}
|
||||
|
||||
m_defaultPath = fileInfo.path() + QLatin1Char('/');
|
||||
m_update.filename = fileName;
|
||||
|
||||
if (parseUpdateFile(fileName))
|
||||
{
|
||||
m_globalUpdatesModel->initModel(m_db, m_update.version, m_update.global_schemas.split(QStringLiteral(",")));
|
||||
m_exercisesModel->initModel(m_db, m_update.version, m_update.exercise_schemas.split(QStringLiteral(",")));
|
||||
m_ui->tbRunUpdate->setEnabled(true);
|
||||
}
|
||||
else
|
||||
ERROR_LOG(m_logger) << "Not a valid update file " << fileName;
|
||||
}
|
||||
|
||||
void DBUpdate::onUpdateRun()
|
||||
{
|
||||
QStringList gSchemas = m_globalUpdatesModel->getSchemasToUpdate();
|
||||
QStringList eSchemas = m_exercisesModel->getSchemasToUpdate();
|
||||
|
||||
// generate SQL
|
||||
m_sql.clear();
|
||||
if (m_update.global_sql.size() > 0 && gSchemas.size() > 0)
|
||||
{
|
||||
for (auto &gs : gSchemas)
|
||||
{
|
||||
m_sql += QStringLiteral("--BEGIN;\n");
|
||||
if (gs != QStringLiteral("PUBLIC"))
|
||||
{
|
||||
QString sUser = QStringLiteral("ets_") + gs;
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + gs + QStringLiteral(" GRANT SELECT,INSERT,UPDATE,DELETE,TRUNCATE ON TABLES TO ") + sUser + QStringLiteral(";\n");
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + gs + QStringLiteral(" GRANT SELECT, REFERENCES ON TABLES TO ") + sUser + QStringLiteral(";\n");
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + gs + QStringLiteral(" GRANT EXECUTE ON FUNCTIONS TO ") + sUser + QStringLiteral(";\n");
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + gs + QStringLiteral(" GRANT ALL ON SEQUENCES TO ") + sUser + QStringLiteral(";\n");
|
||||
}
|
||||
m_sql += QStringLiteral("SET SEARCH_PATH TO %1;\n").arg(gs);
|
||||
m_sql += m_update.global_sql;
|
||||
m_sql += QStringLiteral("\n");
|
||||
m_sql += QStringLiteral("INSERT INTO db_version (description, version) VALUES ('%1', '%2');\n\n").arg(m_update.info, m_update.version);
|
||||
m_sql += QStringLiteral("\n--COMMIT;\n\n");
|
||||
}
|
||||
}
|
||||
if (m_update.exercise_sql.size() > 0 && eSchemas.size() > 0)
|
||||
{
|
||||
for (auto &es : eSchemas)
|
||||
{
|
||||
m_sql += QStringLiteral("--BEGIN;\n");
|
||||
QString sUser = QStringLiteral("ets_ex_00"); // + es;
|
||||
|
||||
m_sql += QStringLiteral("GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA %1 TO %2;\n").arg(es).arg(sUser);
|
||||
m_sql += QStringLiteral("GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA %1 TO %2;\n").arg(es).arg(sUser);
|
||||
m_sql += QStringLiteral("GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA %1 TO %2;\n").arg(es).arg(sUser);
|
||||
|
||||
// backwards compatibility
|
||||
QString sOldUser = QStringLiteral("ets_") + es;
|
||||
m_sql += QStringLiteral("SELECT public.revoke_user_if_exists('%1','%2');\n").arg(sOldUser).arg(es);
|
||||
/*
|
||||
m_sql += QStringLiteral("SELECT create_user_if_not_exists('%1');\n").arg(sOldUser);
|
||||
m_sql += QStringLiteral("REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA %1 FROM %2 CASCADE;\n").arg(es).arg(sOldUser);
|
||||
m_sql += QStringLiteral("REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA %1 FROM %2 CASCADE;\n").arg(es).arg(sOldUser);
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA %1 REVOKE ALL ON TABLES FROM %2;\n").arg(es).arg(sOldUser);
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES FOR ROLE ets_exm IN SCHEMA %1 REVOKE ALL ON TABLES FROM %2;\n").arg(es).arg(sOldUser);
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA %1 REVOKE ALL ON FUNCTIONS FROM %2;\n").arg(es).arg(sOldUser);
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES FOR ROLE ets_exm IN SCHEMA %1 REVOKE ALL ON FUNCTIONS FROM %2;\n").arg(es).arg(sOldUser);
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA %1 REVOKE ALL ON SEQUENCES FROM %2;\n").arg(es).arg(sOldUser);
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES FOR ROLE ets_exm IN SCHEMA %1 REVOKE ALL ON SEQUENCES FROM %2;\n").arg(es).arg(sOldUser);
|
||||
m_sql += QStringLiteral("DROP USER %1;\n").arg(sOldUser);
|
||||
*/
|
||||
// backwards compatibility
|
||||
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + es + QStringLiteral(" GRANT SELECT,INSERT,UPDATE,DELETE,TRUNCATE ON TABLES TO ") + sUser + QStringLiteral(";\n");
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + es + QStringLiteral(" GRANT SELECT, REFERENCES ON TABLES TO ") + sUser + QStringLiteral(";\n");
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + es + QStringLiteral(" GRANT EXECUTE ON FUNCTIONS TO ") + sUser + QStringLiteral(";\n");
|
||||
m_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + es + QStringLiteral(" GRANT ALL ON SEQUENCES TO ") + sUser + QStringLiteral(";\n");
|
||||
|
||||
m_sql += QStringLiteral("SET SEARCH_PATH TO %1;\n").arg(es);
|
||||
m_sql += m_update.exercise_sql;
|
||||
m_sql += QStringLiteral("\n");
|
||||
m_sql += QStringLiteral("INSERT INTO db_version (description, version) VALUES ('%1', '%2');\n\n").arg(m_update.info, m_update.version);
|
||||
m_sql += QStringLiteral("\n--COMMIT;\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (m_sql.size() > 0)
|
||||
{
|
||||
saveUpdateSql();
|
||||
|
||||
DBTransaction transaction(m_db);
|
||||
NSqlQuery q(m_db);
|
||||
|
||||
transaction.begin();
|
||||
|
||||
if (!q.exec(m_sql))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Failed sql: " << m_sql;
|
||||
ERROR_LOG(m_logger) << "Error running sql: " << q.lastError().databaseText() << " " << q.lastError().driverText();
|
||||
transaction.rollback();
|
||||
if (m_showUi)
|
||||
QMessageBox::warning(this, tr("Error!"), tr("An error occurred executing sql. See log file for details."));
|
||||
}
|
||||
else
|
||||
{
|
||||
transaction.commit();
|
||||
if (transaction.state())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "SUCCESS running update: " << m_update.filename;
|
||||
if (m_showUi)
|
||||
QMessageBox::information(this, tr("Success"), tr("Update successful!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
transaction.rollback();
|
||||
if (m_showUi)
|
||||
QMessageBox::warning(this, tr("Error!"), tr("An error occurred executing sql. See log file for details."));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
if (m_showUi)
|
||||
QMessageBox::warning(this, tr("Warning"), tr("Nothing to update."));
|
||||
|
||||
if (m_showUi)
|
||||
enaDisa();
|
||||
}
|
||||
|
||||
void DBUpdate::saveUpdateSql()
|
||||
{
|
||||
QString sqlFile = DBUpdate::m_defaultPath + m_update.version;
|
||||
if (m_update.project.size() > 0)
|
||||
sqlFile += QStringLiteral("_") + m_update.project;
|
||||
sqlFile += QStringLiteral("_run.sql");
|
||||
|
||||
QFile file(sqlFile);
|
||||
if (!file.open(QIODevice::WriteOnly | QFile::Truncate))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error opening file '" << file.fileName() << "' for writing: "
|
||||
<< file.errorString();
|
||||
return ;
|
||||
}
|
||||
|
||||
file.write(m_sql.toUtf8());
|
||||
file.write("\n");
|
||||
|
||||
file.close();
|
||||
|
||||
INFO_LOG(m_logger) << "Saved GENERATED UPDATE FILE: " << sqlFile;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void DBUpdate::onBackupDB()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Creating DB Backup";
|
||||
|
||||
const QString& gVers = m_globalUpdatesModel->getLastUpdate();
|
||||
const QString& eVers = m_exercisesModel->getLastUpdate();
|
||||
|
||||
QString currVersion = ( gVers >= eVers ? gVers : eVers );
|
||||
QString date = QDate::currentDate().toString(QLatin1String("yyyyMMdd"));
|
||||
|
||||
QString dumpFile = DBUpdate::m_defaultPath + m_db.hostName() + QLatin1Char('_') +
|
||||
m_db.databaseName()+ QLatin1Char('_') + date + QLatin1Char('_') + currVersion + QStringLiteral(".dump");
|
||||
|
||||
DBUpdateRun *dbRun = new DBUpdateRun(QString(), false, true);
|
||||
bool backupOK = dbRun->runPgDump(dumpFile, m_db.hostName(), m_db.databaseName());
|
||||
if (!backupOK)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Backup failed";
|
||||
QMessageBox::critical(this, tr("Backup"), tr("Backup failed!"), QMessageBox::Ok);
|
||||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(m_logger) << "Created DB Backup successfully: " << dumpFile;
|
||||
QMessageBox::information(this, tr("Backup"), tr("Successfully created DB backup: %1").arg(dumpFile), QMessageBox::Ok);
|
||||
}
|
||||
delete dbRun;
|
||||
|
||||
}
|
||||
|
||||
void DBUpdate::enaDisa()
|
||||
{
|
||||
if (!m_ui)
|
||||
return;
|
||||
|
||||
// reset UI
|
||||
m_globalUpdatesModel->initModel(m_db);
|
||||
m_exercisesModel->initModel(m_db);
|
||||
m_ui->tbRunUpdate->setEnabled(false);
|
||||
m_ui->lblSelectedUpdate->setText(tr("(no update loaded)"));
|
||||
m_ui->teHeader->clear();
|
||||
m_ui->lblSQL->clear();
|
||||
m_ui->pteSQL->clear();
|
||||
|
||||
m_ui->tvExerciseUpdates->resizeColumnsToContents();
|
||||
m_ui->tvGlobalUpdates->resizeColumnsToContents();
|
||||
|
||||
const QString& gVers = m_globalUpdatesModel->getLastUpdate();
|
||||
const QString& eVers = m_exercisesModel->getLastUpdate();
|
||||
|
||||
int upperGVersion = gVers.split(QLatin1Char('.')).at(0).toInt();
|
||||
int gVersion = gVers.section(QLatin1Char('.'), 1).toInt();
|
||||
DEBUG_LOG(m_logger) << "gVersion: " << gVersion;
|
||||
DEBUG_LOG(m_logger) << "upperGVersion: " << upperGVersion;
|
||||
|
||||
int upperEVersion = eVers.split(QLatin1Char('.')).at(0).toInt();
|
||||
int eVersion = eVers.section(QLatin1Char('.'), 1).toInt();
|
||||
DEBUG_LOG(m_logger) << "eVersion: " << eVersion;
|
||||
DEBUG_LOG(m_logger) << "upperEVersion: " << upperEVersion;
|
||||
|
||||
QString currVersion = eVers;
|
||||
if ( upperGVersion > upperEVersion )
|
||||
currVersion = gVers;
|
||||
else if ( upperGVersion == upperEVersion )
|
||||
currVersion = (gVersion >= eVersion ? gVers : eVers );
|
||||
|
||||
m_ui->lblVersion->setText(currVersion);
|
||||
}
|
||||
|
||||
void DBUpdate::onShowLogFile()
|
||||
{
|
||||
QString logFile = NGL::Settings::logPath() + QStringLiteral("/") + QString::fromLatin1(qgetenv("USER")) + QStringLiteral("_dbu.log");
|
||||
DEBUG_LOG(m_logger) << "onShowLogFile(): " << logFile;
|
||||
|
||||
QFile file(logFile);
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Cannot open file " << logFile;
|
||||
return ;
|
||||
}
|
||||
|
||||
QByteArray output = file.readAll();
|
||||
|
||||
m_ui->pteLogFile->clear();
|
||||
m_ui->pteLogFile->setPlainText(QString::fromLocal8Bit(output));
|
||||
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
|
||||
void DBUpdate::onClearLogFile()
|
||||
{
|
||||
QString logFile = NGL::Settings::logPath() + QStringLiteral("/") + QString::fromLatin1(qgetenv("USER")) + QStringLiteral("_dbu.log");
|
||||
DEBUG_LOG(m_logger) << "onClearLogFile(): " << logFile;
|
||||
|
||||
QFile file(logFile);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QFile::Truncate))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Cannot clear file " << logFile;
|
||||
return ;
|
||||
}
|
||||
|
||||
file.close();
|
||||
m_ui->pteLogFile->clear();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool DBUpdate::parseUpdateFile(const QString &fileName, bool showUi)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "parseUpdateFile: " << fileName;
|
||||
|
||||
QFile file(fileName);
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Cannot read file " << fileName;
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray fileContent = file.readAll();
|
||||
QString updateFile = QString::fromLocal8Bit(fileContent);
|
||||
|
||||
QStringList strUpdate;
|
||||
bool fileOk = true;
|
||||
|
||||
static const QRegularExpression re_info(QStringLiteral("INFO: (.*?)$"), QRegularExpression::MultilineOption);
|
||||
static const QRegularExpression re_date(QStringLiteral("DATE: (.*?)$"), QRegularExpression::MultilineOption);
|
||||
static const QRegularExpression re_vers(QStringLiteral("VERSION: (.*?)$"), QRegularExpression::MultilineOption);
|
||||
static const QRegularExpression re_proj(QStringLiteral("PROJECT: (.*?)$"), QRegularExpression::MultilineOption);
|
||||
static const QRegularExpression re_glob(QStringLiteral("GLOBAL: (.+?);.(.+?COMMIT;)"), QRegularExpression::DotMatchesEverythingOption);
|
||||
static const QRegularExpression re_exer(QStringLiteral("EXERCISE: (.+?);.(.+?COMMIT;)"), QRegularExpression::DotMatchesEverythingOption);
|
||||
|
||||
QRegularExpressionMatch match_info = re_info.match(updateFile);
|
||||
QRegularExpressionMatch match_proj = re_proj.match(updateFile);
|
||||
QRegularExpressionMatch match_vers = re_vers.match(updateFile);
|
||||
QRegularExpressionMatch match_date = re_date.match(updateFile);
|
||||
QRegularExpressionMatch match_glob = re_glob.match(updateFile);
|
||||
QRegularExpressionMatch match_exer = re_exer.match(updateFile);
|
||||
if (match_info.hasMatch() && match_vers.hasMatch() && match_glob.hasMatch() && match_exer.hasMatch())
|
||||
// these are mandatory for a valid update file
|
||||
{
|
||||
strUpdate += match_info.captured(0);
|
||||
strUpdate += match_vers.captured(0);
|
||||
if (match_date.hasMatch())
|
||||
{
|
||||
strUpdate += match_date.captured(0);
|
||||
m_update.date = match_date.captured(1);
|
||||
}
|
||||
if (match_proj.hasMatch())
|
||||
{
|
||||
strUpdate += match_proj.captured(0);
|
||||
m_update.project = match_proj.captured(1).toLower();
|
||||
}
|
||||
|
||||
strUpdate += QStringLiteral("GLOBAL: ") + match_glob.captured(1);
|
||||
strUpdate += QStringLiteral("EXERCISE: ") + match_exer.captured(1);
|
||||
|
||||
m_update.info = match_info.captured(1);
|
||||
m_update.version = match_vers.captured(1);
|
||||
ERROR_LOG(m_logger) << "Update version: " << m_update.version;
|
||||
|
||||
m_update.global_schemas = match_glob.captured(1);
|
||||
m_update.global_sql = match_glob.captured(2);
|
||||
m_update.exercise_schemas = match_exer.captured(1);
|
||||
m_update.exercise_sql = match_exer.captured(2);
|
||||
|
||||
m_update.global_sql.remove(QStringLiteral("BEGIN;"));
|
||||
m_update.global_sql.remove(QStringLiteral("COMMIT;"));
|
||||
m_update.exercise_sql.remove(QStringLiteral("BEGIN;"));
|
||||
m_update.exercise_sql.remove(QStringLiteral("COMMIT;"));
|
||||
}
|
||||
else
|
||||
{
|
||||
fileOk = false;
|
||||
}
|
||||
|
||||
if (fileOk && showUi)
|
||||
{
|
||||
m_ui->lblSelectedUpdate->setText(fileName);
|
||||
m_ui->teHeader->clear();
|
||||
m_ui->teHeader->setText(strUpdate.join(QStringLiteral("\n")));
|
||||
DEBUG_LOG(m_logger) << " teHeader strUpdate: " << strUpdate.join(QStringLiteral("\n"));
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
return fileOk;
|
||||
}
|
||||
|
||||
void DBUpdate::onShowGlobalHistory(const QModelIndex &idx)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onShowHistory";
|
||||
QModelIndex realIdx = m_globalUpdatesProxyModel->mapToSource(idx);
|
||||
const QString &schema = m_globalUpdatesModel->getRowData(realIdx.row()).schema;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Schema = " << schema;
|
||||
|
||||
if (m_showHistory->init(m_db, schema))
|
||||
m_showHistory->show();
|
||||
}
|
||||
|
||||
void DBUpdate::onShowExerciseHistory(const QModelIndex &idx)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onShowHistory";
|
||||
QModelIndex realIdx = m_exercisesProxyModel->mapToSource(idx);
|
||||
const QString &schema = m_exercisesModel->getRowData(realIdx.row()).schema;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Schema = " << schema;
|
||||
|
||||
if (m_showHistory->init(m_db, schema))
|
||||
m_showHistory->show();
|
||||
}
|
||||
|
||||
void DBUpdate::onLoadSQL()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onLoadSQL";
|
||||
|
||||
// open dialog
|
||||
const QStringList filter(
|
||||
{
|
||||
tr("Update Files (*.sql)"),
|
||||
#ifdef Q_OS_WIN
|
||||
tr("All (*.*)")
|
||||
#else
|
||||
tr("All (*)")
|
||||
#endif
|
||||
});
|
||||
|
||||
QString fileName = QFileDialog::getOpenFileName(this,
|
||||
tr("Load sql file"),
|
||||
m_defaultPath,
|
||||
filter.join(QStringLiteral(";;")));
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
QFileInfo fileInfo(fileName);
|
||||
if (!fileInfo.isReadable())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error!"), tr("An error occurred while loading the file.\n"
|
||||
"The loaded file is not readable."));
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(fileName);
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Cannot open file " << fileName;
|
||||
return ;
|
||||
}
|
||||
|
||||
QByteArray output = file.readAll();
|
||||
|
||||
m_ui->lblSQL->setText(fileName);
|
||||
m_ui->pteSQL->clear();
|
||||
m_ui->pteSQL->setPlainText(QString::fromLocal8Bit(output));
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
//===============================================================================================
|
||||
DBUpdateRun::DBUpdateRun(const QString &updateFile, bool generateOnly, bool withBackup, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_generateOnly(generateOnly)
|
||||
, m_withBackup(withBackup)
|
||||
, m_globalUpdatesModel(new GlobalUpdatesModel(this))
|
||||
, m_exercisesModel(new ExercisesModel(this))
|
||||
, m_proc(nullptr)
|
||||
, m_logger(getLogger("DBUpdate"))
|
||||
{
|
||||
m_update.filename = updateFile;
|
||||
}
|
||||
|
||||
DBUpdateRun::~DBUpdateRun()
|
||||
{
|
||||
delete m_globalUpdatesModel;
|
||||
delete m_exercisesModel;
|
||||
}
|
||||
|
||||
bool DBUpdateRun::init()
|
||||
{
|
||||
QString str;
|
||||
NGL::Settings s(str);
|
||||
|
||||
// open postgres db, read table structure, read static data
|
||||
const QString dbUser(QStringLiteral("postgres"));
|
||||
const QString dbPasswd(QStringLiteral("postgres"));
|
||||
m_db = DBConnection::open(m_logger,
|
||||
dbUser,
|
||||
dbPasswd,
|
||||
s.databaseDriver(),
|
||||
s.databaseHostname(),
|
||||
s.databaseName());
|
||||
if (!m_db.isOpen())
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(m_logger) << "DB Open: " << s.databaseHostname() << " / " << s.databaseName();
|
||||
|
||||
m_globalUpdatesModel->initModel(m_db);
|
||||
m_exercisesModel->initModel(m_db);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBUpdateRun::runUpdate()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "runUpdate: " << m_update.filename;
|
||||
bool bRet = false;
|
||||
|
||||
if (m_withBackup)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Creating DB Backup ...";
|
||||
|
||||
const QString& gVers = m_globalUpdatesModel->getLastUpdate();
|
||||
const QString& eVers = m_exercisesModel->getLastUpdate();
|
||||
|
||||
QString currVersion = ( gVers >= eVers ? gVers : eVers );
|
||||
|
||||
QString dumpFile = DBUpdate::m_defaultPath + m_db.hostName() + QLatin1Char('_') +
|
||||
m_db.databaseName()+ QLatin1Char('_') + currVersion + QStringLiteral(".dump");
|
||||
|
||||
if (!runPgDump(dumpFile, m_db.hostName(), m_db.databaseName()))
|
||||
ERROR_LOG(m_logger) << "DB Backup failed!!!";
|
||||
}
|
||||
|
||||
if (parseUpdateFile())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "succesfully parsed update file:" << m_update.filename;
|
||||
|
||||
m_globalUpdatesModel->initModel(m_db, m_update.version, m_update.global_schemas.split(QStringLiteral(",")));
|
||||
m_exercisesModel->initModel(m_db, m_update.version, m_update.exercise_schemas.split(QStringLiteral(",")));
|
||||
|
||||
generateSql();
|
||||
|
||||
if (m_update.generated_file.size() > 0)
|
||||
bRet = true;
|
||||
|
||||
if (!m_generateOnly && bRet)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Running sql file: " << m_update.generated_file;
|
||||
bRet = runPsql();
|
||||
}
|
||||
}
|
||||
return bRet;
|
||||
}
|
||||
|
||||
bool DBUpdateRun::runPsql()
|
||||
{
|
||||
const QStringList args({QStringLiteral("-U"),
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("-f"),
|
||||
m_update.generated_file,
|
||||
QStringLiteral("-h"),
|
||||
m_db.hostName(),
|
||||
m_db.databaseName()});
|
||||
|
||||
handleProcInit(executablePath(QStringLiteral("psql")), args);
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &DBUpdateRun::onPsqlFinished);
|
||||
m_proc->start();
|
||||
return m_proc->waitForFinished();
|
||||
}
|
||||
|
||||
bool DBUpdateRun::runPgDump(const QString& dumpFile, const QString& dbHost, const QString& dbName)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Backup file = " << dumpFile;
|
||||
|
||||
const QStringList args(
|
||||
{ QStringLiteral("--column-inserts"),
|
||||
QStringLiteral("-U"), QStringLiteral("postgres"),
|
||||
QStringLiteral("-f"), dumpFile,
|
||||
QStringLiteral("-h"), dbHost, dbName});
|
||||
|
||||
handleProcInit(executablePath(QStringLiteral("pg_dump")), args);
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &DBUpdateRun::onPgDumpFinished);
|
||||
m_proc->start();
|
||||
return m_proc->waitForFinished();
|
||||
}
|
||||
|
||||
QString DBUpdateRun::executablePath(const QString &program)
|
||||
{
|
||||
QString errStr;
|
||||
const QString ret = NGL::postgresExecutablePath(program, errStr);
|
||||
if (!errStr.isEmpty())
|
||||
WARNING_LOG(m_logger) << errStr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DBUpdateRun::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, &DBUpdateRun::onErrorOccured);
|
||||
}
|
||||
|
||||
void DBUpdateRun::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 DBUpdateRun::onPsqlFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
NOTICE_LOG(m_logger) << "onPsqlFinished: exitCode: " << exitCode << ", exitStatus: " << exitStatus;
|
||||
|
||||
if (exitCode > 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Psql failed";
|
||||
emit runSqlFailed();
|
||||
return;
|
||||
}
|
||||
emit runSqlFinished();
|
||||
}
|
||||
|
||||
void DBUpdateRun::onPgDumpFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
NOTICE_LOG(m_logger) << "onPgDumpFinished: exitCode: " << exitCode << ", exitStatus: " << exitStatus;
|
||||
|
||||
if (exitCode > 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Backup (pg_dump) failed";
|
||||
emit runPgDumpFailed();
|
||||
return;
|
||||
}
|
||||
ERROR_LOG(m_logger) << "Backup successfully finished!";
|
||||
emit runPgDumpFinished();
|
||||
}
|
||||
|
||||
void DBUpdateRun::onErrorOccured(QProcess::ProcessError error)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "error: " << error << ", " << m_proc->readAllStandardOutput() << ", " << m_proc->readAllStandardError();
|
||||
}
|
||||
|
||||
bool DBUpdateRun::parseUpdateFile()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "parseUpdateFile: " << m_update.filename;
|
||||
|
||||
QFile file(m_update.filename);
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Cannot read file " << m_update.filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray fileContent = file.readAll();
|
||||
QString updateFile = QString::fromLocal8Bit(fileContent);
|
||||
|
||||
QStringList strUpdate;
|
||||
bool fileOk = true;
|
||||
|
||||
static const QRegularExpression re_info(QStringLiteral("INFO: (.*?)$"), QRegularExpression::MultilineOption);
|
||||
static const QRegularExpression re_date(QStringLiteral("DATE: (.*?)$"), QRegularExpression::MultilineOption);
|
||||
static const QRegularExpression re_vers(QStringLiteral("VERSION: (.*?)$"), QRegularExpression::MultilineOption);
|
||||
static const QRegularExpression re_proj(QStringLiteral("PROJECT: (.*?)$"), QRegularExpression::MultilineOption);
|
||||
static const QRegularExpression re_glob(QStringLiteral("GLOBAL: (.+?);.(.+?COMMIT;)"), QRegularExpression::DotMatchesEverythingOption);
|
||||
static const QRegularExpression re_exer(QStringLiteral("EXERCISE: (.+?);.(.+?COMMIT;)"), QRegularExpression::DotMatchesEverythingOption);
|
||||
|
||||
QRegularExpressionMatch match_info = re_info.match(updateFile);
|
||||
QRegularExpressionMatch match_vers = re_vers.match(updateFile);
|
||||
QRegularExpressionMatch match_date = re_date.match(updateFile);
|
||||
QRegularExpressionMatch match_glob = re_glob.match(updateFile);
|
||||
QRegularExpressionMatch match_exer = re_exer.match(updateFile);
|
||||
QRegularExpressionMatch match_proj = re_proj.match(updateFile);
|
||||
|
||||
if (match_info.hasMatch() && match_vers.hasMatch() && match_glob.hasMatch() && match_exer.hasMatch())
|
||||
// these are mandatory for a valid update file
|
||||
{
|
||||
strUpdate += match_info.captured(0);
|
||||
strUpdate += match_vers.captured(0);
|
||||
if (match_date.hasMatch())
|
||||
{
|
||||
strUpdate += match_date.captured(0);
|
||||
m_update.date = match_date.captured(1);
|
||||
}
|
||||
if (match_proj.hasMatch())
|
||||
{
|
||||
strUpdate += match_proj.captured(0);
|
||||
m_update.project = match_proj.captured(1).toLower();
|
||||
}
|
||||
|
||||
strUpdate += QStringLiteral("GLOBAL: ") + match_glob.captured(1);
|
||||
strUpdate += QStringLiteral("EXERCISE: ") + match_exer.captured(1);
|
||||
|
||||
m_update.info = match_info.captured(1);
|
||||
m_update.version = match_vers.captured(1);
|
||||
m_update.global_schemas = match_glob.captured(1);
|
||||
m_update.global_sql = match_glob.captured(2);
|
||||
m_update.exercise_schemas = match_exer.captured(1);
|
||||
m_update.exercise_sql = match_exer.captured(2);
|
||||
|
||||
m_update.global_sql.remove(QStringLiteral("BEGIN;"));
|
||||
m_update.global_sql.remove(QStringLiteral("COMMIT;"));
|
||||
m_update.exercise_sql.remove(QStringLiteral("BEGIN;"));
|
||||
m_update.exercise_sql.remove(QStringLiteral("COMMIT;"));
|
||||
}
|
||||
else
|
||||
{
|
||||
fileOk = false;
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
return fileOk;
|
||||
}
|
||||
|
||||
void DBUpdateRun::generateSql()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "generateSql:";
|
||||
|
||||
QStringList gSchemas = m_globalUpdatesModel->getSchemasToUpdate();
|
||||
QStringList eSchemas = m_exercisesModel->getSchemasToUpdate();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Global schemas: " << gSchemas.join(QStringLiteral(","));
|
||||
DEBUG_LOG(m_logger) << "Exercise schemas: " << gSchemas.join(QStringLiteral(","));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Global sql: " << m_update.global_sql;
|
||||
DEBUG_LOG(m_logger) << "Exercise sql: " << m_update.exercise_sql;
|
||||
|
||||
// generate SQL
|
||||
m_update.generated_sql.clear();
|
||||
if (m_update.global_sql.size() > 0 && gSchemas.size() > 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Global sql: " << m_update.global_sql;
|
||||
|
||||
for (auto &gs : gSchemas)
|
||||
{
|
||||
m_update.generated_sql += QStringLiteral("--BEGIN;\n");
|
||||
if (gs != QStringLiteral("PUBLIC"))
|
||||
{
|
||||
QString sUser = QStringLiteral("ets_") + gs;
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + gs + QStringLiteral(" GRANT SELECT,INSERT,UPDATE,DELETE,TRUNCATE ON TABLES TO ") + sUser + QStringLiteral(";\n");
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + gs + QStringLiteral(" GRANT SELECT, REFERENCES ON TABLES TO ") + sUser + QStringLiteral(";\n");
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + gs + QStringLiteral(" GRANT EXECUTE ON FUNCTIONS TO ") + sUser + QStringLiteral(";\n");
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + gs + QStringLiteral(" GRANT ALL ON SEQUENCES TO ") + sUser + QStringLiteral(";\n");
|
||||
}
|
||||
}
|
||||
m_update.generated_sql += QStringLiteral("SET SEARCH_PATH TO %1;\n").arg(gSchemas.join(QStringLiteral(",")));
|
||||
m_update.generated_sql += m_update.global_sql;
|
||||
m_update.generated_sql += QStringLiteral("\n");
|
||||
m_update.generated_sql += QStringLiteral("INSERT INTO db_version (description, version) VALUES ('%1', '%2');\n\n").arg(m_update.info, m_update.version);
|
||||
m_update.generated_sql += QStringLiteral("\n--COMMIT;\n\n");
|
||||
}
|
||||
if (m_update.exercise_sql.size() > 0 && eSchemas.size() > 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Exercise sql: " << m_update.exercise_sql;
|
||||
|
||||
for (auto &es : eSchemas)
|
||||
{
|
||||
m_update.generated_sql += QStringLiteral("--BEGIN;\n");
|
||||
QString sUser = QStringLiteral("ets_ex_00"); // + es;
|
||||
|
||||
m_update.generated_sql += QStringLiteral("GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA %1 TO %2;\n").arg(es).arg(sUser);
|
||||
m_update.generated_sql += QStringLiteral("GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA %1 TO %2;\n").arg(es).arg(sUser);
|
||||
m_update.generated_sql += QStringLiteral("GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA %1 TO %2;\n").arg(es).arg(sUser);
|
||||
|
||||
//backwards compatibility
|
||||
QString sOldUser = QStringLiteral("ets_") + es;
|
||||
m_update.generated_sql += QStringLiteral("SELECT public.revoke_user_if_exists('%1','%2');\n").arg(sOldUser).arg(es);
|
||||
/*
|
||||
m_update.generated_sql += QStringLiteral("SELECT create_user_if_not_exists('%1');\n").arg(sOldUser);
|
||||
m_update.generated_sql += QStringLiteral("REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA %1 FROM %2 CASCADE;\n").arg(es).arg(sOldUser);
|
||||
m_update.generated_sql += QStringLiteral("REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA %1 FROM %2 CASCADE;\n").arg(es).arg(sOldUser);
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA %1 REVOKE ALL ON TABLES FROM %2;\n").arg(es).arg(sOldUser);
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES FOR ROLE ets_exm IN SCHEMA %1 REVOKE ALL ON TABLES FROM %2;\n").arg(es).arg(sOldUser);
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA %1 REVOKE ALL ON FUNCTIONS FROM %2;\n").arg(es).arg(sOldUser);
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES FOR ROLE ets_exm IN SCHEMA %1 REVOKE ALL ON FUNCTIONS FROM %2;\n").arg(es).arg(sOldUser);
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA %1 REVOKE ALL ON SEQUENCES FROM %2;\n").arg(es).arg(sOldUser);
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES FOR ROLE ets_exm IN SCHEMA %1 REVOKE ALL ON SEQUENCES FROM %2;\n").arg(es).arg(sOldUser);
|
||||
m_update.generated_sql += QStringLiteral("DROP USER %1;\n").arg(sOldUser);
|
||||
*/
|
||||
//backwards compatibility
|
||||
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + es + QStringLiteral(" GRANT SELECT,INSERT,UPDATE,DELETE,TRUNCATE ON TABLES TO ") + sUser + QStringLiteral(";\n");
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + es + QStringLiteral(" GRANT SELECT, REFERENCES ON TABLES TO ") + sUser + QStringLiteral(";\n");
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + es + QStringLiteral(" GRANT EXECUTE ON FUNCTIONS TO ") + sUser + QStringLiteral(";\n");
|
||||
m_update.generated_sql += QStringLiteral("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + es + QStringLiteral(" GRANT ALL ON SEQUENCES TO ") + sUser + QStringLiteral(";\n");
|
||||
|
||||
m_update.generated_sql += QStringLiteral("SET SEARCH_PATH TO %1;\n").arg(es);
|
||||
m_update.generated_sql += m_update.exercise_sql;
|
||||
m_update.generated_sql += QStringLiteral("\n");
|
||||
m_update.generated_sql += QStringLiteral("INSERT INTO db_version (description, version) VALUES ('%1', '%2');\n\n").arg(m_update.info, m_update.version);
|
||||
m_update.generated_sql += QStringLiteral("\n--COMMIT;\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Generated sql size: " << m_update.generated_sql.size();
|
||||
|
||||
if (m_update.generated_sql.size() > 0)
|
||||
{
|
||||
QString sqlFile = DBUpdate::m_defaultPath + m_update.version;
|
||||
if (m_update.project.size() > 0)
|
||||
sqlFile += QStringLiteral("_") + m_update.project;
|
||||
sqlFile += QStringLiteral("_run.sql");
|
||||
|
||||
QFile file(sqlFile);
|
||||
if (file.open(QIODevice::WriteOnly | QFile::Truncate))
|
||||
{
|
||||
file.write(m_update.generated_sql.toUtf8());
|
||||
file.write("\n");
|
||||
|
||||
file.close();
|
||||
INFO_LOG(m_logger) << "Saved GENERATED UPDATE FILE: " << sqlFile;
|
||||
m_update.generated_file = sqlFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error opening file '" << file.fileName() << "' for writing: "
|
||||
<< file.errorString();
|
||||
m_update.generated_file = QString();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace DBUpdate
|
||||
Reference in new issue
Block a user