Permalink
Browse files

Add initial support for multiple database schemata

This adds initial basic support for handling different database schemata
at once to the backend code. This is still far from working properly but
shouldn't break much either - mostly because it's not really used yet in
the user interface code.
  • Loading branch information...
MKleusberg committed Sep 2, 2017
1 parent 4339119 commit 532fcd3f6b713e89f7739f25de09c353c61bbe99
@@ -142,7 +142,7 @@ void DbStructureModel::reloadData()

QTreeWidgetItem* itemBrowsables = new QTreeWidgetItem(rootItem);
itemBrowsables->setIcon(0, QIcon(QString(":/icons/view")));
itemBrowsables->setText(0, tr("Browsables (%1)").arg(m_db.objMap.values("table").count() + m_db.objMap.values("view").count()));
itemBrowsables->setText(0, tr("Browsables (%1)").arg(m_db.schemata["main"].values("table").count() + m_db.schemata["main"].values("view").count()));
typeToParentItem.insert("browsable", itemBrowsables);

QTreeWidgetItem* itemAll = new QTreeWidgetItem(rootItem);
@@ -151,27 +151,27 @@ void DbStructureModel::reloadData()

QTreeWidgetItem* itemTables = new QTreeWidgetItem(itemAll);
itemTables->setIcon(0, QIcon(QString(":/icons/table")));
itemTables->setText(0, tr("Tables (%1)").arg(m_db.objMap.values("table").count()));
itemTables->setText(0, tr("Tables (%1)").arg(m_db.schemata["main"].values("table").count()));
typeToParentItem.insert("table", itemTables);

QTreeWidgetItem* itemIndices = new QTreeWidgetItem(itemAll);
itemIndices->setIcon(0, QIcon(QString(":/icons/index")));
itemIndices->setText(0, tr("Indices (%1)").arg(m_db.objMap.values("index").count()));
itemIndices->setText(0, tr("Indices (%1)").arg(m_db.schemata["main"].values("index").count()));
typeToParentItem.insert("index", itemIndices);

QTreeWidgetItem* itemViews = new QTreeWidgetItem(itemAll);
itemViews->setIcon(0, QIcon(QString(":/icons/view")));
itemViews->setText(0, tr("Views (%1)").arg(m_db.objMap.values("view").count()));
itemViews->setText(0, tr("Views (%1)").arg(m_db.schemata["main"].values("view").count()));
typeToParentItem.insert("view", itemViews);

QTreeWidgetItem* itemTriggers = new QTreeWidgetItem(itemAll);
itemTriggers->setIcon(0, QIcon(QString(":/icons/trigger")));
itemTriggers->setText(0, tr("Triggers (%1)").arg(m_db.objMap.values("trigger").count()));
itemTriggers->setText(0, tr("Triggers (%1)").arg(m_db.schemata["main"].values("trigger").count()));
typeToParentItem.insert("trigger", itemTriggers);

// Get all database objects and sort them by their name
QMultiMap<QString, sqlb::ObjectPtr> dbobjs;
for(auto it=m_db.objMap.constBegin(); it != m_db.objMap.constEnd(); ++it)
for(auto it=m_db.schemata["main"].constBegin(); it != m_db.schemata["main"].constEnd(); ++it)
dbobjs.insert((*it)->name(), (*it));

// Add the actual table objects
@@ -238,7 +238,7 @@ QMimeData* DbStructureModel::mimeData(const QModelIndexList& indices) const
if(data(index.sibling(index.row(), 1), Qt::DisplayRole).toString() == "table")
{
SqliteTableModel tableModel(m_db);
tableModel.setTable(data(index.sibling(index.row(), 0), Qt::DisplayRole).toString());
tableModel.setTable(sqlb::ObjectIdentifier("main", data(index.sibling(index.row(), 0), Qt::DisplayRole).toString()));
for(int i=0; i < tableModel.rowCount(); ++i)
{
QString insertStatement = "INSERT INTO " + sqlb::escapeIdentifier(data(index.sibling(index.row(), 0), Qt::DisplayRole).toString()) + " VALUES(";
@@ -19,7 +19,7 @@ EditIndexDialog::EditIndexDialog(DBBrowserDB& db, const QString& indexName, bool

// Get list of tables, sort it alphabetically and fill the combobox
objectMap dbobjs;
QList<sqlb::ObjectPtr> tables = pdb.objMap.values("table");
QList<sqlb::ObjectPtr> tables = pdb.schemata["main"].values("table");
for(auto it=tables.constBegin();it!=tables.constEnd();++it)
dbobjs.insert((*it)->name(), (*it));
ui->comboTableName->blockSignals(true);
@@ -34,7 +34,7 @@ EditIndexDialog::EditIndexDialog(DBBrowserDB& db, const QString& indexName, bool
if(!newIndex)
{
// Load the current layout and fill in the dialog fields
index = *(pdb.getObjectByName(curIndex).dynamicCast<sqlb::Index>());
index = *(pdb.getObjectByName(sqlb::ObjectIdentifier("main", curIndex)).dynamicCast<sqlb::Index>());

ui->editIndexName->blockSignals(true);
ui->editIndexName->setText(index.name());
@@ -94,7 +94,7 @@ void EditIndexDialog::tableChanged(const QString& new_table, bool initialLoad)
void EditIndexDialog::updateColumnLists()
{
// Fill the table column list
sqlb::FieldInfoList tableFields = pdb.getObjectByName(index.table()).dynamicCast<sqlb::Table>()->fieldInformation();
sqlb::FieldInfoList tableFields = pdb.getObjectByName(sqlb::ObjectIdentifier("main", index.table())).dynamicCast<sqlb::Table>()->fieldInformation();
ui->tableTableColumns->setRowCount(tableFields.size());
int tableRows = 0;
for(int i=0;i<tableFields.size();++i)
@@ -33,7 +33,7 @@ EditTableDialog::EditTableDialog(DBBrowserDB& db, const QString& tableName, bool
if(m_bNewTable == false)
{
// Existing table, so load and set the current layout
m_table = *(pdb.getObjectByName(curTable).dynamicCast<sqlb::Table>());
m_table = *(pdb.getObjectByName(sqlb::ObjectIdentifier("main", curTable)).dynamicCast<sqlb::Table>());
ui->labelEditWarning->setVisible(!m_table.fullyParsed());

// Set without rowid and temporary checkboxex. No need to trigger any events here as we're only loading a table exactly as it is stored by SQLite, so no need
@@ -163,7 +163,7 @@ void EditTableDialog::accept()
// Rename table if necessary
if(ui->editTableName->text() != curTable)
{
if(!pdb.renameTable(curTable, ui->editTableName->text()))
if(!pdb.renameTable("main", curTable, ui->editTableName->text()))
{
QMessageBox::warning(this, QApplication::applicationName(), pdb.lastError());
return;
@@ -210,7 +210,7 @@ void EditTableDialog::checkInput()
if (oldTableName == fk->table()) {
fk->setTable(normTableName);
if(!fksEnabled)
pdb.renameColumn(curTable, m_table, f->name(), f, 0);
pdb.renameColumn(sqlb::ObjectIdentifier("main", curTable), m_table, f->name(), f, 0);
}
}
}
@@ -239,7 +239,7 @@ void EditTableDialog::updateTypes()

m_table.fields().at(index)->setType(type);
if(!m_bNewTable)
pdb.renameColumn(curTable, m_table, column, m_table.fields().at(index));
pdb.renameColumn(sqlb::ObjectIdentifier("main", curTable), m_table, column, m_table.fields().at(index));
checkInput();
}
}
@@ -279,7 +279,7 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
if(!m_bNewTable)
{
sqlb::FieldVector pk = m_table.primaryKey();
foreach(const sqlb::ObjectPtr& fkobj, pdb.objMap.values("table"))
foreach(const sqlb::ObjectPtr& fkobj, pdb.schemata["main"].values("table"))
{
QList<sqlb::ConstraintPtr> fks = fkobj.dynamicCast<sqlb::Table>()->constraints(sqlb::FieldVector(), sqlb::Constraint::ForeignKeyConstraintType);
foreach(sqlb::ConstraintPtr fkptr, fks)
@@ -352,8 +352,9 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
// we need to check for this case and cancel here. Maybe we can think of some way to modify the INSERT INTO ... SELECT statement
// to at least replace all troublesome NULL values by the default value
SqliteTableModel m(pdb, this);
m.setQuery(QString("SELECT COUNT(%1) FROM %2 WHERE %3 IS NULL;")
.arg(sqlb::escapeIdentifier(pdb.getObjectByName(curTable).dynamicCast<sqlb::Table>()->rowidColumn()))
m.setQuery(QString("SELECT COUNT(%1) FROM %2.%3 WHERE %4 IS NULL;")
.arg(sqlb::escapeIdentifier(pdb.getObjectByName(sqlb::ObjectIdentifier("main", curTable)).dynamicCast<sqlb::Table>()->rowidColumn()))
.arg(sqlb::escapeIdentifier("main"))
.arg(sqlb::escapeIdentifier(curTable))
.arg(sqlb::escapeIdentifier(field->name())));
if(m.data(m.index(0, 0)).toInt() > 0)
@@ -489,7 +490,7 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)

if(callRenameColumn)
{
if(!pdb.renameColumn(curTable, m_table, oldFieldName, field))
if(!pdb.renameColumn(sqlb::ObjectIdentifier("main", curTable), m_table, oldFieldName, field))
QMessageBox::warning(this, qApp->applicationName(), tr("Modifying this column failed. Error returned from database:\n%1").arg(pdb.lastError()));
}
}
@@ -548,7 +549,7 @@ void EditTableDialog::addField()

// Actually add the new column to the table if we're editing an existing table
if(!m_bNewTable)
pdb.addColumn(curTable, f);
pdb.addColumn(sqlb::ObjectIdentifier("main", curTable), f);

checkInput();
}
@@ -576,12 +577,12 @@ void EditTableDialog::removeField()
QString msg = tr("Are you sure you want to delete the field '%1'?\nAll data currently stored in this field will be lost.").arg(ui->treeWidget->currentItem()->text(0));
if(QMessageBox::warning(this, QApplication::applicationName(), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)
{
if(!pdb.renameColumn(curTable, m_table, ui->treeWidget->currentItem()->text(0), sqlb::FieldPtr()))
if(!pdb.renameColumn(sqlb::ObjectIdentifier("main", curTable), m_table, ui->treeWidget->currentItem()->text(0), sqlb::FieldPtr()))
{
QMessageBox::warning(0, QApplication::applicationName(), pdb.lastError());
} else {
//relayout
m_table = *(pdb.getObjectByName(curTable).dynamicCast<sqlb::Table>());
m_table = *(pdb.getObjectByName(sqlb::ObjectIdentifier("main", curTable)).dynamicCast<sqlb::Table>());
populateFields();
}
}
@@ -654,7 +655,7 @@ void EditTableDialog::moveCurrentField(bool down)

// Move the actual column
if(!pdb.renameColumn(
curTable,
sqlb::ObjectIdentifier("main", curTable),
m_table,
ui->treeWidget->currentItem()->text(0),
m_table.fields().at(ui->treeWidget->indexOfTopLevelItem(ui->treeWidget->currentItem())),
@@ -664,7 +665,7 @@ void EditTableDialog::moveCurrentField(bool down)
QMessageBox::warning(0, QApplication::applicationName(), pdb.lastError());
} else {
// Reload table SQL
m_table = *(pdb.getObjectByName(curTable).dynamicCast<sqlb::Table>());
m_table = *(pdb.getObjectByName(sqlb::ObjectIdentifier("main", curTable)).dynamicCast<sqlb::Table>());
populateFields();

// Select old item at new position
@@ -710,7 +711,7 @@ void EditTableDialog::setWithoutRowid(bool without_rowid)
// Update table if we're editing an existing table
if(!m_bNewTable)
{
if(!pdb.renameColumn(curTable, m_table, QString(), sqlb::FieldPtr(), 0))
if(!pdb.renameColumn(sqlb::ObjectIdentifier("main", curTable), m_table, QString(), sqlb::FieldPtr(), 0))
{
QMessageBox::warning(this, QApplication::applicationName(),
tr("Setting the rowid column for the table failed. Error message:\n%1").arg(pdb.lastError()));
@@ -729,7 +730,7 @@ void EditTableDialog::setTemporary(bool is_temp)
// Update table if we're editing an existing table
if(!m_bNewTable)
{
if(!pdb.renameColumn(curTable, m_table, QString(), sqlb::FieldPtr(), 0))
if(!pdb.renameColumn(sqlb::ObjectIdentifier("main", curTable), m_table, QString(), sqlb::FieldPtr(), 0))
{
QMessageBox::warning(this, QApplication::applicationName(),
tr("Setting the temporary flag for the table failed. Error message:\n%1").arg(pdb.lastError()));
@@ -42,7 +42,7 @@ ExportDataDialog::ExportDataDialog(DBBrowserDB& db, ExportFormats format, QWidge
if(query.isEmpty())
{
// Get list of tables to export
objectMap objects = pdb.getBrowsableObjects();
objectMap objects = pdb.getBrowsableObjects("main");
foreach(const sqlb::ObjectPtr& obj, objects)
ui->listTables->addItem(new QListWidgetItem(QIcon(QString(":icons/%1").arg(sqlb::Object::typeToString(obj->type()))), obj->name()));

@@ -34,10 +34,9 @@ ExportSqlDialog::ExportSqlDialog(DBBrowserDB* db, QWidget* parent, const QString
ui->comboOldSchema->setCurrentIndex(settings.value(sSettingsOldSchema, 0).toInt());

// Get list of tables to export
objectMap objects = pdb->getBrowsableObjects();
for(auto it=objects.constBegin();it!=objects.constEnd();++it) {
objectMap objects = pdb->getBrowsableObjects("main");
for(auto it=objects.constBegin();it!=objects.constEnd();++it)
ui->listTables->addItem(new QListWidgetItem(QIcon(QString(":icons/%1").arg((*it)->type())), (*it)->name()));
}

// Sort list of tables and select the table specified in the
// selection parameter or all tables if table not specified
@@ -81,7 +81,7 @@ ForeignKeyEditorDelegate::ForeignKeyEditorDelegate(const DBBrowserDB& db, sqlb::
, m_db(db)
, m_table(table)
{
const auto objects = m_db.getBrowsableObjects();
const auto objects = m_db.getBrowsableObjects("main");
for (auto& obj : objects) {
if (obj->type() == sqlb::Object::Types::Table) {
QString tableName = obj->name();
@@ -394,7 +394,7 @@ void ImportCsvDialog::importCsv(const QString& fileName, const QString &name)

// Are we importing into an existing table?
bool importToExistingTable = false;
const sqlb::ObjectPtr obj = pdb->getObjectByName(tableName);
const sqlb::ObjectPtr obj = pdb->getObjectByName(sqlb::ObjectIdentifier("main", tableName));
if(obj && obj->type() == sqlb::Object::Types::Table)
{
if((size_t)obj.dynamicCast<sqlb::Table>()->fields().size() != csv.columns())
@@ -425,14 +425,14 @@ void ImportCsvDialog::importCsv(const QString& fileName, const QString &name)
QStringList nullValues;
if(!importToExistingTable)
{
if(!pdb->createTable(tableName, fieldList))
if(!pdb->createTable(sqlb::ObjectIdentifier("main", tableName), fieldList))
return rollback(this, pdb, progress, restorepointName, 0, tr("Creating the table failed: %1").arg(pdb->lastError()));
} else {
// Importing into an existing table. So find out something about it's structure.

// Prepare the values for each table column that are to be inserted if the field in the CSV file is empty. Depending on the data type
// and the constraints of a field, we need to handle this case differently.
sqlb::TablePtr tbl = pdb->getObjectByName(tableName).dynamicCast<sqlb::Table>();
sqlb::TablePtr tbl = pdb->getObjectByName(sqlb::ObjectIdentifier("main", tableName)).dynamicCast<sqlb::Table>();
if(tbl)
{
foreach(const sqlb::FieldPtr& f, tbl->fields())
Oops, something went wrong.

0 comments on commit 532fcd3

Please sign in to comment.