Add table prefix to be prepended to each table

This allows multiple independent xca databases in one database
This commit is contained in:
Christian Hohnstaedt 2018-03-18 16:42:35 +01:00
parent 468f7e43e2
commit 64c9c5ccab
7 changed files with 100 additions and 32 deletions

View File

@ -9,6 +9,7 @@
#include <QDebug>
#include "base.h"
#include "sql.h"
#include "settings.h"
int DbTransaction::mutex;
int DbTransaction::error;
@ -99,12 +100,48 @@ bool DbTransaction::done(QSqlError e, const char *file, int line)
return e.isValid() ? rollback(file, line) : commit(file, line);
}
QString XSqlQuery::table_prefix;
int XSqlQuery::schemaVersion()
{
qDebug() << "table_prefix:" << table_prefix;;
return QSqlDatabase::database().tables()
.contains(table_prefix + "settings") ?
Settings["schema"] : 0;
}
QString XSqlQuery::rewriteQuery(QString _q)
{
QStringList tables; tables <<
"items" << "crls" << "private_keys" << "public_keys" <<
"tokens" << "token_mechanism" << "templates" << "certs" <<
"authority" << "revocations" << "requests" << "x509super" <<
"settings" << "revocations" <<
"view_public_keys" << "view_certs" << "view_requests" <<
"view_crls" << "view_templates" << "view_private" ;
lastq = query = _q;
if (table_prefix.isEmpty())
return query;
QString m = tables.join("|") + "|i_" + tables.join("|i_");
m = QString("\\b(%1)").arg(m);
query = query.replace(QRegExp(m), table_prefix + "\\1");
return query;
}
QString XSqlQuery::query_details()
{
QString lq = lastq;
QList<QVariant> list = boundValues().values();
QStringList sl;
if (query != lastq) {
lq = QString("%1 (PREFIX[%2]: %3)").arg(lastq)
.arg(table_prefix).arg(query);
}
for (int i = 0; i < list.size(); ++i)
sl << list.at(i).toString();
if (sl.size())
@ -126,15 +163,14 @@ XSqlQuery::XSqlQuery() : QSqlQuery()
{
}
XSqlQuery::XSqlQuery(QString q) : QSqlQuery(q)
XSqlQuery::XSqlQuery(QString q) : QSqlQuery()
{
file = ""; line = 0;
lastq = q;
exec(q);
}
bool XSqlQuery::exec(QString q)
{
lastq = q;
q = rewriteQuery(q);
file = ""; line = 0;
return QSqlQuery::exec(q);
}
@ -159,7 +195,7 @@ bool XSqlQuery::exec()
bool XSqlQuery::prepare(QString q)
{
lastq = q;
q = rewriteQuery(q);
setForwardOnly(true);
return QSqlQuery::prepare(q);
}

View File

@ -56,13 +56,24 @@ class DbTransaction
class XSqlQuery: public QSqlQuery
{
private:
QString lastq;
QString lastq, query;
const char *file;
int line;
QString rewriteQuery(QString query);
static QString table_prefix;
public:
XSqlQuery();
XSqlQuery(QString q);
static int schemaVersion();
static void setTablePrefix(QString p)
{
table_prefix = p;
}
static void clearTablePrefix()
{
table_prefix.clear();
}
QString query_details();
QSqlError lastError();
bool exec(QString q);

View File

@ -7,12 +7,9 @@
<x>0</x>
<y>0</y>
<width>441</width>
<height>325</height>
<height>292</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="_2">
@ -149,6 +146,16 @@
<item row="4" column="1">
<widget class="QLineEdit" name="dbName"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Table prefix</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="prefix"/>
</item>
</layout>
</item>
<item>

View File

@ -32,24 +32,18 @@ QSqlError MainWindow::initSqlDB()
XSqlQuery q;
QSqlDatabase db = QSqlDatabase::database();
QStringList tables;
unsigned i = 0;
unsigned int i;
if (!db.isOpen())
return QSqlError();
tables = db.tables();
if (tables.contains("settings")) {
i = Settings["schema"];
}
Transaction;
if (!TransBegin())
return db.lastError();
for (; i < ARRAY_SIZE(schemas); i++) {
for (i = XSqlQuery::schemaVersion(); i < ARRAY_SIZE(schemas); i++) {
foreach(QString sql, schemas[i]) {
qDebug("EXEC[%d]: '%s'", i, CCHAR(sql));
if (!q.exec(sql)) {
if (!q.exec(sql) || q.lastError().isValid()) {
TransRollback();
return q.lastError();
}
@ -66,13 +60,14 @@ QString MainWindow::openSqlDB(QString dbName)
close_database();
opendb->openDatabase();
QSqlError e = initSqlDB();
qDebug() << "DB-DESC:" << opendb->getDescriptor();
if (e.isValid()) {
dbSqlError();
dbSqlError(e);
QSqlDatabase::database().close();
dbName = QString();
} else {
dbName = opendb->getDescriptor();
}
qDebug() << "DB-DESC:" << opendb->getDescriptor() << dbName << e;
}
delete opendb;
return dbName;
@ -258,7 +253,7 @@ int MainWindow::init_database(QString dbName)
}
Entropy::seed_rng();
dbName = openSqlDB(dbName);
if (!QSqlDatabase::database().isOpen()) {
if (!QSqlDatabase::database().isOpen() || dbName.isEmpty()) {
/* Error already printed */
return 1;
}
@ -513,6 +508,7 @@ void MainWindow::close_database()
QSqlDatabase::removeDatabase(connName);
currentDB.clear();
Settings.clear();
XSqlQuery::clearTablePrefix();
}
void MainWindow::load_history()

View File

@ -15,6 +15,9 @@
#include "PwDialog.h"
#include "lib/base.h"
#define NUM_PARAM 6
#define NUM_PARAM_LEAST 5
DbMap OpenDb::getDatabases()
{
QStringList list = QSqlDatabase::drivers();
@ -46,17 +49,21 @@ bool OpenDb::hasRemoteDrivers()
DbMap OpenDb::splitRemoteDbName(QString db)
{
static const char * const names[] =
{ "all", "user", "host", "type", "dbname" };
static const char * const names[NUM_PARAM] =
{ "all", "user", "host", "type", "dbname", "prefix" };
DbMap map;
QRegExp rx("(.*)@(.*)/(.*):(.*)");
QRegExp rx("(.*)@(.*)/(.*):([^#]*)#?([^#]*)");
int i, pos = rx.indexIn(db);
QStringList list = rx.capturedTexts();
if (pos != -1 && list.size() == 5) {
for (i=0; i<5; i++) {
if (pos != -1 && list.size() >= NUM_PARAM_LEAST) {
if (list.size() == NUM_PARAM_LEAST)
list[NUM_PARAM_LEAST] = "";
list[NUM_PARAM_LEAST] = list[NUM_PARAM_LEAST].toLower();
for (i=0; i < NUM_PARAM; i++) {
map[names[i]] = list[i];
}
qDebug() << "SPLIT DB:" << map;
}
return map;
}
@ -64,7 +71,7 @@ DbMap OpenDb::splitRemoteDbName(QString db)
bool OpenDb::isRemoteDB(QString db)
{
DbMap remote_param = splitRemoteDbName(db);
return remote_param.size() == 5;
return remote_param.size() == NUM_PARAM;
}
OpenDb::OpenDb(QWidget *parent, QString db)
@ -77,11 +84,12 @@ OpenDb::OpenDb(QWidget *parent, QString db)
setWindowTitle(XCA_TITLE);
remote_param = splitRemoteDbName(db);
if (remote_param.size() == 5) {
if (remote_param.size() == NUM_PARAM) {
userName->setText(remote_param["user"]);
hostName->setText(remote_param["host"]);
dbTypeName = remote_param["type"];
dbName->setText(remote_param["dbname"]);
prefix->setText(remote_param["prefix"]);
sqlite = false;
show_connection_settings = false;
} else if (hasSqLite() && !db.isEmpty()) {
@ -183,26 +191,31 @@ bool OpenDb::_openDatabase(QString connName, QString pass) const
db.setPort(hostport[1].toInt());
db.setUserName(userName->text());
db.setPassword(pass);
XSqlQuery::setTablePrefix(prefix->text().toLower());
db.open();
QSqlError e = db.lastError();
if (!e.isValid() || e.type() != QSqlError::ConnectionError ||
db.isOpen())
return true;
XSqlQuery::clearTablePrefix();
db.close();
return false;
};
QString OpenDb::getDescriptor() const
{
QString pref = prefix->text();
if (!pref.isEmpty())
pref = QString("#%1").arg(pref.toLower());
return sqlite ?
dbName->text() :
QString("%1@%2/%3:%4")
QString("%1@%2/%3:%4%5")
.arg(userName->text())
.arg(hostName->text())
.arg(getDbType())
.arg(dbName->text());
.arg(dbName->text())
.arg(pref);
}
int OpenDb::exec()

View File

@ -9,6 +9,7 @@
#define __OPENDB_H
#include "ui_OpenDb.h"
#include <QDialog>
#include <QSqlDatabase>
typedef QMap<QString, QString> DbMap;

View File

@ -294,3 +294,7 @@
<< "CREATE INDEX i_items_stamp ON items (stamp)"
<< "UPDATE settings SET value='5' WHERE key_='schema'"
;
/* When adding new tables or views, also add them to the list
* in XSqlQuery::rewriteQuery(QString) in lib/sql.cpp
*/