Basic support for passing postgresql uri on the commandline
This commit is contained in:
parent
4b4c95e57e
commit
4caccf1000
11 changed files with 453 additions and 192 deletions
|
|
@ -1,16 +1,19 @@
|
|||
#include "ConnectionListModel.h"
|
||||
#include "ScopeGuard.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <botan/cryptobox.h>
|
||||
#include <QDir>
|
||||
#include <QException>
|
||||
#include <QMimeData>
|
||||
#include <QSettings>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlError>
|
||||
#include <QSqlQuery>
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
#include <QStandardPaths>
|
||||
#include <QStringBuilder>
|
||||
#include <unordered_set>
|
||||
|
||||
|
||||
namespace {
|
||||
|
|
@ -41,6 +44,16 @@ CREATE TABLE IF NOT EXISTS connection (
|
|||
password TEXT
|
||||
);)__";
|
||||
|
||||
const char * const q_create_table_migrations =
|
||||
R"__(
|
||||
CREATE TABLE IF NOT EXISTS _migration (
|
||||
migration_id TEXT PRIMARY KEY
|
||||
);)__";
|
||||
|
||||
const char * const q_load_migrations_present =
|
||||
R"__(
|
||||
SELECT migration_id
|
||||
FROM _migration;)__";
|
||||
|
||||
|
||||
const char * const q_insert_or_replace_into_connection =
|
||||
|
|
@ -49,21 +62,136 @@ R"__(INSERT OR REPLACE INTO connection
|
|||
:sslmode, :sslcert, :sslkey, :sslrootcert, :sslcrl, :password);
|
||||
)__" ;
|
||||
|
||||
std::tuple<bool, QSqlError> InitConnectionTables(QSqlDatabase &db)
|
||||
{
|
||||
QSqlQuery q_create_table(db);
|
||||
q_create_table.prepare(q_create_table_conngroup);
|
||||
if (!q_create_table.exec()) {
|
||||
auto err = q_create_table.lastError();
|
||||
return { false, err };
|
||||
}
|
||||
q_create_table.prepare(q_create_table_connection);
|
||||
if (!q_create_table.exec()) {
|
||||
auto err = q_create_table.lastError();
|
||||
return { false, err };
|
||||
}
|
||||
return {true, {}};
|
||||
}
|
||||
|
||||
// Keeping migration function name and id DRY
|
||||
#define APPLY_MIGRATION(id) ApplyMigration(#id, &MigrationDirector::id)
|
||||
|
||||
class MigrationDirector {
|
||||
public:
|
||||
explicit MigrationDirector(QSqlDatabase &db)
|
||||
: db(db)
|
||||
{
|
||||
}
|
||||
|
||||
void Execute()
|
||||
{
|
||||
InitConnectionTables();
|
||||
present = LoadMigrations();
|
||||
APPLY_MIGRATION(M20250215_0933_Parameters);
|
||||
}
|
||||
|
||||
private:
|
||||
QSqlDatabase &db;
|
||||
std::unordered_set<QString> present;
|
||||
|
||||
void M20250215_0933_Parameters()
|
||||
{
|
||||
Exec(R"__(
|
||||
CREATE TABLE connection_parameter (
|
||||
connection_uuid TEXT,
|
||||
pname TEXT,
|
||||
pvalue TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY(connection_uuid, pname)
|
||||
);)__");
|
||||
|
||||
|
||||
for (QString key : { "host", "hostaddr", "user", "dbname", "sslmode", "sslcert", "sslkey", "sslrootcert", "sslcrl" })
|
||||
{
|
||||
Exec(
|
||||
"INSERT INTO connection_parameter (connection_uuid, pname, pvalue)"
|
||||
" SELECT uuid, '" % key % "', " % key % "\n"
|
||||
" FROM connection\n"
|
||||
" WHERE " % key % " IS NOT NULL and " % key % " <> '';");
|
||||
}
|
||||
Exec(R"__(
|
||||
INSERT INTO connection_parameter (connection_uuid, pname, pvalue)
|
||||
SELECT uuid, 'port', port
|
||||
FROM connection
|
||||
WHERE port IS NOT NULL;
|
||||
)__");
|
||||
|
||||
for (QString column : { "host", "hostaddr", "user", "dbname", "sslmode", "sslcert", "sslkey", "sslrootcert", "sslcrl", "port" })
|
||||
{
|
||||
// sqlite does not seem to support dropping more then one column per alter table
|
||||
Exec("ALTER TABLE connection DROP COLUMN " % column % ";");
|
||||
}
|
||||
}
|
||||
|
||||
void Exec(QString query)
|
||||
{
|
||||
QSqlQuery q(query, db);
|
||||
Verify(q);
|
||||
}
|
||||
|
||||
void ApplyMigration(QString migration_id, void (MigrationDirector::*func)())
|
||||
{
|
||||
if (!present.contains(migration_id))
|
||||
{
|
||||
if (!db.transaction())
|
||||
{
|
||||
throw std::runtime_error("Failed to start transaction on user configuration database");
|
||||
}
|
||||
(this->*func)();
|
||||
RegisterMigration(migration_id);
|
||||
if (!db.commit())
|
||||
{
|
||||
db.rollback();
|
||||
throw std::runtime_error("Failed to commit transaction on user configuration database");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<QString> LoadMigrations()
|
||||
{
|
||||
std::unordered_set<QString> result;
|
||||
QSqlQuery q(q_load_migrations_present, db);
|
||||
Verify(q);
|
||||
while (q.next())
|
||||
{
|
||||
result.insert(q.value(0).toString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void RegisterMigration(QString migrationId)
|
||||
{
|
||||
const char * const q_register_migration =
|
||||
R"__(INSERT INTO _migration VALUES (:id);)__" ;
|
||||
|
||||
QSqlQuery q(db);
|
||||
q.prepare(q_register_migration);
|
||||
q.bindValue(":id", migrationId);
|
||||
if (!q.exec()) {
|
||||
Verify(q);
|
||||
}
|
||||
}
|
||||
|
||||
void Verify(QSqlQuery &q)
|
||||
{
|
||||
auto err = q.lastError();
|
||||
if (err.type() == QSqlError::NoError)
|
||||
return;
|
||||
|
||||
db.rollback();
|
||||
QString errString = err.text();
|
||||
throw std::runtime_error(errString.toStdString());
|
||||
}
|
||||
|
||||
void InitConnectionTables()
|
||||
{
|
||||
// Original schema
|
||||
QSqlQuery q_create_table(db);
|
||||
q_create_table.exec(q_create_table_conngroup);
|
||||
Verify(q_create_table);
|
||||
q_create_table.exec(q_create_table_connection);
|
||||
Verify(q_create_table);
|
||||
// Start using migrations
|
||||
q_create_table.exec(q_create_table_migrations);
|
||||
Verify(q_create_table);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
std::optional<QSqlError> SaveConnectionConfig(QSqlDatabase &db, const ConnectionConfig &cc, int conngroup_id)
|
||||
{
|
||||
|
|
@ -105,7 +233,9 @@ ConnectionTreeModel::ConnectionTreeModel(QObject *parent, QSqlDatabase &db)
|
|||
|
||||
void ConnectionTreeModel::load()
|
||||
{
|
||||
InitConnectionTables(m_db);
|
||||
//InitConnectionTables(m_db);
|
||||
MigrationDirector md(m_db);
|
||||
md.Execute();
|
||||
|
||||
QSqlQuery q(m_db);
|
||||
q.prepare("SELECT conngroup_id, gname FROM conngroup;");
|
||||
|
|
@ -124,9 +254,7 @@ void ConnectionTreeModel::load()
|
|||
m_groups.push_back(g);
|
||||
}
|
||||
|
||||
q.prepare("SELECT uuid, cname, conngroup_id, host, hostaddr, port, "
|
||||
" user, dbname, sslmode, sslcert, sslkey, sslrootcert, sslcrl, "
|
||||
" password "
|
||||
q.prepare("SELECT uuid, cname, conngroup_id, password "
|
||||
"FROM connection ORDER BY conngroup_id, cname;");
|
||||
if (!q.exec()) {
|
||||
// auto err = q_create_table.lastError();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue