Use some more SQL containers instead of their Qt equivalents

This commit is contained in:
Martin Kleusberg
2019-04-26 14:57:44 +02:00
parent f59a2453a2
commit 15c23bb0d3
36 changed files with 974 additions and 962 deletions
+11 -12
View File
@@ -181,7 +181,7 @@ void AddRecordDialog::populateFields()
sqlb::FieldVector fields;
std::vector<sqlb::ConstraintPtr> fks;
QStringList pk;
sqlb::StringVector pk;
// Initialize fields, fks and pk differently depending on whether it's a table or a view.
const sqlb::ObjectPtr obj = pdb.getObjectByName(curTable);
@@ -196,8 +196,7 @@ void AddRecordDialog::populateFields()
sqlb::ViewPtr m_view = pdb.getObjectByName<sqlb::View>(curTable);
fields = m_view->fields;
fks.resize(fields.size(), sqlb::ConstraintPtr(nullptr));
for(const auto& col : pseudo_pk)
pk << QString::fromStdString(col);
pk = pseudo_pk;
}
for(uint i = 0; i < fields.size(); i++)
@@ -207,9 +206,9 @@ void AddRecordDialog::populateFields()
tbitem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);
tbitem->setText(kName, f.name());
tbitem->setText(kType, f.type());
tbitem->setData(kType, Qt::UserRole, f.affinity());
tbitem->setText(kName, QString::fromStdString(f.name()));
tbitem->setText(kType, QString::fromStdString(f.type()));
tbitem->setData(kType, Qt::UserRole, QString::fromStdString(f.affinity()));
// NOT NULL fields are indicated in bold.
if (f.notnull()) {
@@ -224,7 +223,7 @@ void AddRecordDialog::populateFields()
else
tbitem->setIcon(kName, QIcon(":/icons/field"));
QString defaultValue = f.defaultValue();
QString defaultValue = QString::fromStdString(f.defaultValue());
QString toolTip;
if (f.autoIncrement())
@@ -233,19 +232,19 @@ void AddRecordDialog::populateFields()
if (f.unique())
toolTip.append(tr("Unique constraint\n"));
if (!f.check().isEmpty())
toolTip.append(tr("Check constraint:\t %1\n").arg (f.check()));
if (!f.check().empty())
toolTip.append(tr("Check constraint:\t %1\n").arg(QString::fromStdString(f.check())));
auto fk = std::dynamic_pointer_cast<sqlb::ForeignKeyClause>(fks[i]);
if(fk)
toolTip.append(tr("Foreign key:\t %1\n").arg(fk->toString()));
toolTip.append(tr("Foreign key:\t %1\n").arg(QString::fromStdString(fk->toString())));
setDefaultsStyle(tbitem);
// Display Role is used for displaying the default values.
// Only when they are changed, the User Role is updated and then used in the INSERT query.
if (!defaultValue.isEmpty()) {
tbitem->setData(kValue, Qt::DisplayRole, f.defaultValue());
tbitem->setData(kValue, Qt::DisplayRole, QString::fromStdString(f.defaultValue()));
toolTip.append(tr("Default value:\t %1\n").arg (defaultValue));
} else
tbitem->setData(kValue, Qt::DisplayRole, Settings::getValue("databrowser", "null_text"));
@@ -281,7 +280,7 @@ void AddRecordDialog::accept()
void AddRecordDialog::updateSqlText()
{
QString stmt = QString("INSERT INTO %1").arg(curTable.toString());
QString stmt = QString("INSERT INTO %1").arg(QString::fromStdString(curTable.toString()));
QStringList vals;
QStringList fields;
+1 -1
View File
@@ -117,7 +117,7 @@ void ColumnDisplayFormatDialog::accept()
// Return false so the query is not aborted and no error is reported.
return false;
};
if(!pdb.executeSQL(QString("SELECT %1 FROM %2 LIMIT 1").arg(ui->editDisplayFormat->text(), curTable.toString()),
if(!pdb.executeSQL(QString("SELECT %1 FROM %2 LIMIT 1").arg(ui->editDisplayFormat->text(), QString::fromStdString(curTable.toString())),
false, true, callback))
errorMessage = tr("Error in custom display format. Message from database engine:\n\n%1").arg(pdb.lastError());
else if(customNumberColumns != 1)
+4 -4
View File
@@ -9,7 +9,7 @@
#include <QPushButton>
#include <QMessageBox>
CondFormatManager::CondFormatManager(const QVector<CondFormat>& condFormats, const QString& encoding, QWidget *parent) :
CondFormatManager::CondFormatManager(const std::vector<CondFormat>& condFormats, const QString& encoding, QWidget *parent) :
QDialog(parent),
ui(new Ui::CondFormatManager),
m_condFormats(condFormats),
@@ -97,16 +97,16 @@ void CondFormatManager::downItem()
ui->tableCondFormats->currentIndex().column()));
}
QVector<CondFormat> CondFormatManager::getCondFormats()
std::vector<CondFormat> CondFormatManager::getCondFormats()
{
QVector<CondFormat> result;
std::vector<CondFormat> result;
for (int i = 0; i < ui->tableCondFormats->topLevelItemCount(); ++i)
{
QTreeWidgetItem* item = ui->tableCondFormats->topLevelItem(i);
CondFormat aCondFormat(item->text(ColumnFilter),
item->background(ColumnForeground).color(),
item->background(ColumnBackground).color(), m_encoding);
result.append(aCondFormat);
result.push_back(aCondFormat);
}
return result;
}
+4 -3
View File
@@ -2,6 +2,7 @@
#define CONDFORMATMANAGER_H
#include <QDialog>
#include <vector>
#include "Palette.h"
@@ -18,10 +19,10 @@ class CondFormatManager : public QDialog
Q_OBJECT
public:
explicit CondFormatManager(const QVector<CondFormat>& condFormats, const QString& encoding, QWidget *parent = nullptr);
explicit CondFormatManager(const std::vector<CondFormat>& condFormats, const QString& encoding, QWidget *parent = nullptr);
~CondFormatManager() override;
QVector<CondFormat> getCondFormats();
std::vector<CondFormat> getCondFormats();
private:
enum Columns {
ColumnForeground = 0,
@@ -29,7 +30,7 @@ private:
ColumnFilter = 2
};
Ui::CondFormatManager *ui;
QVector<CondFormat> m_condFormats;
std::vector<CondFormat> m_condFormats;
Palette m_condFormatPalette;
QString m_encoding;
+19 -19
View File
@@ -47,7 +47,7 @@ QVariant DbStructureModel::data(const QModelIndex& index, int role) const
// for schemata != "main"). For the normal structure branch of the tree we don't want to add the schema name because it's already obvious from
// the position of the item in the tree.
if(index.column() == ColumnName && item->parent() == browsablesRootItem)
return sqlb::ObjectIdentifier(item->text(ColumnSchema), item->text(ColumnName)).toDisplayString();
return QString::fromStdString(sqlb::ObjectIdentifier(item->text(ColumnSchema).toStdString(), item->text(ColumnName).toStdString()).toDisplayString());
else
return Settings::getValue("db", "hideschemalinebreaks").toBool() ? item->text(index.column()).replace("\n", " ").simplified() : item->text(index.column());
case Qt::EditRole:
@@ -186,7 +186,7 @@ void DbStructureModel::reloadData()
{
QTreeWidgetItem* itemSchema = new QTreeWidgetItem(itemAll);
itemSchema->setIcon(ColumnName, QIcon(QString(":/icons/database")));
itemSchema->setText(ColumnName, it.key());
itemSchema->setText(ColumnName, QString::fromStdString(it.key()));
itemSchema->setText(ColumnObjectType, "database");
buildTree(itemSchema, it.key());
}
@@ -236,8 +236,8 @@ QMimeData* DbStructureModel::mimeData(const QModelIndexList& indices) const
if(objectType == "table")
{
SqliteTableModel tableModel(m_db);
sqlb::ObjectIdentifier objid(data(index.sibling(index.row(), ColumnSchema), Qt::DisplayRole).toString(),
data(index.sibling(index.row(), ColumnName), Qt::DisplayRole).toString());
sqlb::ObjectIdentifier objid(data(index.sibling(index.row(), ColumnSchema), Qt::DisplayRole).toString().toStdString(),
data(index.sibling(index.row(), ColumnName), Qt::DisplayRole).toString().toStdString());
tableModel.setQuery(sqlb::Query(objid));
if(tableModel.completeCache())
{
@@ -245,7 +245,7 @@ QMimeData* DbStructureModel::mimeData(const QModelIndexList& indices) const
for(int i=0; i < tableModel.rowCount(); ++i)
{
QString insertStatement = "INSERT INTO " + objid.toString() + " VALUES(";
QString insertStatement = "INSERT INTO " + QString::fromStdString(objid.toString()) + " VALUES(";
for(int j=1; j < tableModel.columnCount(); ++j)
insertStatement += QString("'%1',").arg(tableModel.data(tableModel.index(i, j), Qt::EditRole).toString());
insertStatement.chop(1);
@@ -300,10 +300,10 @@ bool DbStructureModel::dropMimeData(const QMimeData* data, Qt::DropAction action
}
}
void DbStructureModel::buildTree(QTreeWidgetItem* parent, const QString& schema)
void DbStructureModel::buildTree(QTreeWidgetItem* parent, const std::string& schema)
{
// Build a map from object type to tree node to simplify finding the correct tree node later
QMap<QString, QTreeWidgetItem*> typeToParentItem;
QMap<std::string, QTreeWidgetItem*> typeToParentItem;
// Get object map for the given schema
objectMap objmap = m_db.schemata[schema];
@@ -330,7 +330,7 @@ void DbStructureModel::buildTree(QTreeWidgetItem* parent, const QString& schema)
typeToParentItem.insert("trigger", itemTriggers);
// Get all database objects and sort them by their name
QMultiMap<QString, sqlb::ObjectPtr> dbobjs;
QMultiMap<std::string, sqlb::ObjectPtr> dbobjs;
for(auto it : objmap)
dbobjs.insert(it->name(), it);
@@ -348,7 +348,7 @@ void DbStructureModel::buildTree(QTreeWidgetItem* parent, const QString& schema)
sqlb::FieldInfoList fieldList = it->fieldInformation();
if(!fieldList.empty())
{
QStringList pk_columns;
sqlb::StringVector pk_columns;
if(it->type() == sqlb::Object::Types::Table)
pk_columns = std::dynamic_pointer_cast<sqlb::Table>(it)->primaryKey();
for(const sqlb::FieldInfo& field : fieldList)
@@ -358,12 +358,12 @@ void DbStructureModel::buildTree(QTreeWidgetItem* parent, const QString& schema)
if(it->type() == sqlb::Object::Types::Table)
isFK = std::dynamic_pointer_cast<sqlb::Table>(it)->constraint({field.name}, sqlb::Constraint::ForeignKeyConstraintType) != nullptr;
fldItem->setText(ColumnName, field.name);
fldItem->setText(ColumnName, QString::fromStdString(field.name));
fldItem->setText(ColumnObjectType, "field");
fldItem->setText(ColumnDataType, field.type);
fldItem->setText(ColumnSQL, field.sql);
fldItem->setText(ColumnSchema, schema);
if(pk_columns.contains(field.name))
fldItem->setText(ColumnDataType, QString::fromStdString(field.type));
fldItem->setText(ColumnSQL, QString::fromStdString(field.sql));
fldItem->setText(ColumnSchema, QString::fromStdString(schema));
if(contains(pk_columns, field.name))
fldItem->setIcon(ColumnName, QIcon(":/icons/field_key"));
else if(isFK)
fldItem->setIcon(ColumnName, QIcon(":/icons/field_fk"));
@@ -374,16 +374,16 @@ void DbStructureModel::buildTree(QTreeWidgetItem* parent, const QString& schema)
}
}
QTreeWidgetItem* DbStructureModel::addNode(QTreeWidgetItem* parent, const sqlb::ObjectPtr& object, const QString& schema)
QTreeWidgetItem* DbStructureModel::addNode(QTreeWidgetItem* parent, const sqlb::ObjectPtr& object, const std::string& schema)
{
QString type = sqlb::Object::typeToString(object->type());
QString type = QString::fromStdString(sqlb::Object::typeToString(object->type()));
QTreeWidgetItem *item = new QTreeWidgetItem(parent);
item->setIcon(ColumnName, QIcon(QString(":/icons/%1").arg(type)));
item->setText(ColumnName, object->name());
item->setText(ColumnName, QString::fromStdString(object->name()));
item->setText(ColumnObjectType, type);
item->setText(ColumnSQL, object->originalSql());
item->setText(ColumnSchema, schema);
item->setText(ColumnSQL, QString::fromStdString(object->originalSql()));
item->setText(ColumnSchema, QString::fromStdString(schema));
return item;
}
+2 -2
View File
@@ -52,8 +52,8 @@ private:
bool m_dropQualifiedNames;
bool m_dropEnquotedNames;
void buildTree(QTreeWidgetItem* parent, const QString& schema);
QTreeWidgetItem* addNode(QTreeWidgetItem* parent, const sqlb::ObjectPtr& object, const QString& schema);
void buildTree(QTreeWidgetItem* parent, const std::string& schema);
QTreeWidgetItem* addNode(QTreeWidgetItem* parent, const sqlb::ObjectPtr& object, const std::string& schema);
QString getNameForDropping(const QString& domain, const QString& object, const QString& field) const;
};
+23 -23
View File
@@ -19,7 +19,7 @@ EditIndexDialog::EditIndexDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
ui->sqlTextEdit->setReadOnly(true);
// Get list of tables, sort it alphabetically and fill the combobox
QMap<QString, sqlb::ObjectIdentifier> dbobjs; // Map from display name to full object identifier
QMap<std::string, sqlb::ObjectIdentifier> dbobjs; // Map from display name to full object identifier
if(newIndex) // If this is a new index, offer all tables of all database schemata
{
for(auto it=pdb.schemata.constBegin();it!=pdb.schemata.constEnd();++it)
@@ -43,7 +43,7 @@ EditIndexDialog::EditIndexDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
}
ui->comboTableName->blockSignals(true);
for(auto it=dbobjs.constBegin();it!=dbobjs.constEnd();++it)
ui->comboTableName->addItem(QIcon(QString(":icons/table")), it.key(), it.value().toVariant());
ui->comboTableName->addItem(QIcon(QString(":icons/table")), QString::fromStdString(it.key()), QString::fromStdString(it.value().toSerialised()));
ui->comboTableName->blockSignals(false);
QHeaderView *tableHeaderView = ui->tableIndexColumns->horizontalHeader();
@@ -56,19 +56,19 @@ EditIndexDialog::EditIndexDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
index = *(pdb.getObjectByName<sqlb::Index>(curIndex));
ui->editIndexName->blockSignals(true);
ui->editIndexName->setText(index.name());
ui->editIndexName->setText(QString::fromStdString(index.name()));
ui->editIndexName->blockSignals(false);
ui->checkIndexUnique->blockSignals(true);
ui->checkIndexUnique->setChecked(index.unique());
ui->checkIndexUnique->blockSignals(false);
ui->comboTableName->blockSignals(true);
ui->comboTableName->setCurrentText(index.table());
ui->comboTableName->setCurrentText(QString::fromStdString(index.table()));
ui->comboTableName->blockSignals(false);
ui->editPartialClause->blockSignals(true);
ui->editPartialClause->setText(index.whereExpr());
ui->editPartialClause->setText(QString::fromStdString(index.whereExpr()));
ui->editPartialClause->blockSignals(false);
tableChanged(index.table(), true);
tableChanged(QString::fromStdString(index.table()), true);
} else {
tableChanged(ui->comboTableName->currentText(), false);
}
@@ -77,7 +77,7 @@ EditIndexDialog::EditIndexDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
connect(ui->tableIndexColumns, &QTableWidget::itemChanged,
[=](QTableWidgetItem* item)
{
index.fields[item->row()].setName(item->text());
index.fields[item->row()].setName(item->text().toStdString());
updateSqlText();
});
@@ -95,7 +95,7 @@ void EditIndexDialog::tableChanged(const QString& new_table, bool initialLoad)
// Set the table name and clear all index columns
if(!initialLoad)
{
index.setTable(sqlb::ObjectIdentifier(ui->comboTableName->currentData()).name());
index.setTable(sqlb::ObjectIdentifier(ui->comboTableName->currentData().toString().toStdString()).name());
index.fields.clear();
}
@@ -113,7 +113,7 @@ void EditIndexDialog::tableChanged(const QString& new_table, bool initialLoad)
void EditIndexDialog::updateColumnLists()
{
// Fill the table column list
sqlb::TablePtr table = pdb.getObjectByName<sqlb::Table>(sqlb::ObjectIdentifier(ui->comboTableName->currentData()));
sqlb::TablePtr table = pdb.getObjectByName<sqlb::Table>(sqlb::ObjectIdentifier(ui->comboTableName->currentData().toString().toStdString()));
if(!table)
return;
sqlb::FieldInfoList tableFields = table->fieldInformation();
@@ -127,12 +127,12 @@ void EditIndexDialog::updateColumnLists()
if(sqlb::findField(index, tableFields.at(i).name) == index.fields.end())
{
// Put the name of the field in the first column
QTableWidgetItem* name = new QTableWidgetItem(tableFields.at(i).name);
QTableWidgetItem* name = new QTableWidgetItem(QString::fromStdString(tableFields.at(i).name));
name->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
ui->tableTableColumns->setItem(tableRows, 0, name);
// Put the data type in the second column
QTableWidgetItem* type = new QTableWidgetItem(tableFields.at(i).type);
QTableWidgetItem* type = new QTableWidgetItem(QString::fromStdString(tableFields.at(i).type));
type->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
ui->tableTableColumns->setItem(tableRows, 1, type);
@@ -151,7 +151,7 @@ void EditIndexDialog::updateColumnLists()
for(size_t i=0;i<indexFields.size();++i)
{
// Put the name of the field in the first column
QTableWidgetItem* name = new QTableWidgetItem(indexFields.at(i).name());
QTableWidgetItem* name = new QTableWidgetItem(QString::fromStdString(indexFields.at(i).name()));
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if(indexFields.at(i).expression())
flags |= Qt::ItemIsEditable;
@@ -163,7 +163,7 @@ void EditIndexDialog::updateColumnLists()
order->addItem("");
order->addItem("ASC");
order->addItem("DESC");
order->setCurrentText(indexFields.at(i).order().toUpper());
order->setCurrentText(QString::fromStdString(indexFields.at(i).order()).toUpper());
ui->tableIndexColumns->setCellWidget(i, 1, order);
connect(order, &QComboBox::currentTextChanged,
[=](QString new_order)
@@ -171,7 +171,7 @@ void EditIndexDialog::updateColumnLists()
auto colnum = sqlb::findField(index, indexFields.at(i).name());
if(colnum != index.fields.end())
{
colnum->setOrder(new_order);
colnum->setOrder(new_order.toStdString());
updateSqlText();
}
});
@@ -196,9 +196,9 @@ void EditIndexDialog::addToIndex(const QModelIndex& idx)
// Add field to index
index.fields.emplace_back(
ui->tableTableColumns->item(row, 0)->text(), // Column name
false, // Is expression
""); // Order
ui->tableTableColumns->item(row, 0)->text().toStdString(), // Column name
false, // Is expression
""); // Order
// Update UI
updateColumnLists();
@@ -227,7 +227,7 @@ void EditIndexDialog::removeFromIndex(const QModelIndex& idx)
}
// Remove column from index
sqlb::removeField(index, ui->tableIndexColumns->item(row, 0)->text());
sqlb::removeField(index, ui->tableIndexColumns->item(row, 0)->text().toStdString());
// Update UI
updateColumnLists();
@@ -252,9 +252,9 @@ void EditIndexDialog::checkInput()
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid);
// Set the index name and the unique flag
index.setName(ui->editIndexName->text());
index.setName(ui->editIndexName->text().toStdString());
index.setUnique(ui->checkIndexUnique->isChecked());
index.setWhereExpr(ui->editPartialClause->text());
index.setWhereExpr(ui->editPartialClause->text().toStdString());
updateSqlText();
}
@@ -263,7 +263,7 @@ void EditIndexDialog::accept()
// When editing an index, delete the old one first
if(!newIndex)
{
if(!pdb.executeSQL(QString("DROP INDEX IF EXISTS %1;").arg(curIndex.toString())))
if(!pdb.executeSQL(QString("DROP INDEX IF EXISTS %1;").arg(QString::fromStdString(curIndex.toString()))))
{
QMessageBox::warning(this, qApp->applicationName(), tr("Deleting the old index failed:\n%1").arg(pdb.lastError()));
return;
@@ -271,7 +271,7 @@ void EditIndexDialog::accept()
}
// Create the new index in the schema of the selected table
if(pdb.executeSQL(index.sql(sqlb::ObjectIdentifier(ui->comboTableName->currentData()).schema())))
if(pdb.executeSQL(QString::fromStdString(index.sql(sqlb::ObjectIdentifier(ui->comboTableName->currentData().toString().toStdString()).schema()))))
QDialog::accept();
else
QMessageBox::warning(this, QApplication::applicationName(), tr("Creating the index failed:\n%1").arg(pdb.lastError()));
@@ -287,7 +287,7 @@ void EditIndexDialog::reject()
void EditIndexDialog::updateSqlText()
{
ui->sqlTextEdit->setText(index.sql(sqlb::ObjectIdentifier(ui->comboTableName->currentData()).schema()));
ui->sqlTextEdit->setText(QString::fromStdString(index.sql(sqlb::ObjectIdentifier(ui->comboTableName->currentData().toString().toStdString()).schema())));
}
void EditIndexDialog::moveColumnUp()
+56 -54
View File
@@ -43,7 +43,7 @@ EditTableDialog::EditTableDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
// Initialise the list of tracked columns for table layout changes
for(const auto& field : m_table.fields)
trackColumns[field.name()] = field.name();
trackColumns[QString::fromStdString(field.name())] = QString::fromStdString(field.name());
// Set without rowid checkbox and schema dropdown. No need to trigger any events here as we're only loading a table exactly as it is stored by SQLite, so no need
// for error checking etc.
@@ -51,14 +51,16 @@ EditTableDialog::EditTableDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
ui->checkWithoutRowid->setChecked(m_table.withoutRowidTable());
ui->checkWithoutRowid->blockSignals(false);
ui->comboSchema->blockSignals(true);
ui->comboSchema->addItems(pdb.schemata.keys()); // Load list of database schemata
ui->comboSchema->setCurrentText(curTable.schema());
for(const auto& n : pdb.schemata.keys()) // Load list of database schemata
ui->comboSchema->addItem(QString::fromStdString(n));
ui->comboSchema->setCurrentText(QString::fromStdString(curTable.schema()));
ui->comboSchema->blockSignals(false);
populateFields();
populateConstraints();
} else {
ui->comboSchema->addItems(pdb.schemata.keys()); // Load list of database schemata
for(const auto& n : pdb.schemata.keys()) // Load list of database schemata
ui->comboSchema->addItem(QString::fromStdString(n));
ui->comboSchema->setCurrentText("main"); // Always create tables in the main schema by default
ui->labelEditWarning->setVisible(false);
}
@@ -67,7 +69,7 @@ EditTableDialog::EditTableDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
pdb.setSavepoint(m_sRestorePointName);
// Update UI
ui->editTableName->setText(curTable.name());
ui->editTableName->setText(QString::fromStdString(curTable.name()));
updateColumnWidth();
checkInput();
@@ -116,21 +118,21 @@ void EditTableDialog::populateFields()
ui->treeWidget->clear();
const auto& fields = m_table.fields;
QStringList pk = m_table.primaryKey();
sqlb::StringVector pk = m_table.primaryKey();
for(const sqlb::Field& f : fields)
{
QTreeWidgetItem *tbitem = new QTreeWidgetItem(ui->treeWidget);
tbitem->setFlags(tbitem->flags() | Qt::ItemIsEditable);
tbitem->setText(kName, f.name());
tbitem->setText(kName, QString::fromStdString(f.name()));
QComboBox* typeBox = new QComboBox(ui->treeWidget);
typeBox->setProperty("column", f.name());
typeBox->setProperty("column", QString::fromStdString(f.name()));
typeBox->setEditable(true);
typeBox->addItems(DBBrowserDB::Datatypes);
int index = typeBox->findText(f.type(), Qt::MatchExactly);
int index = typeBox->findText(QString::fromStdString(f.type()), Qt::MatchExactly);
if(index == -1)
{
// non standard named type
typeBox->addItem(f.type());
typeBox->addItem(QString::fromStdString(f.type()));
index = typeBox->count() - 1;
}
typeBox->setCurrentIndex(index);
@@ -146,16 +148,16 @@ void EditTableDialog::populateFields()
// For the default value check if it is surrounded by parentheses and if that's the case
// add a '=' character before the entire string to match the input format we're expecting
// from the user when using functions in the default value field.
if(f.defaultValue().startsWith('(') && f.defaultValue().endsWith(')'))
tbitem->setText(kDefault, "=" + f.defaultValue());
if(f.defaultValue().front() == '(' && f.defaultValue().back() == ')')
tbitem->setText(kDefault, "=" + QString::fromStdString(f.defaultValue()));
else
tbitem->setText(kDefault, f.defaultValue());
tbitem->setText(kDefault, QString::fromStdString(f.defaultValue()));
tbitem->setText(kCheck, f.check());
tbitem->setText(kCheck, QString::fromStdString(f.check()));
auto fk = std::dynamic_pointer_cast<sqlb::ForeignKeyClause>(m_table.constraint({f.name()}, sqlb::Constraint::ForeignKeyConstraintType));
if(fk)
tbitem->setText(kForeignKey, fk->toString());
tbitem->setText(kForeignKey, QString::fromStdString(fk->toString()));
ui->treeWidget->addTopLevelItem(tbitem);
}
@@ -176,7 +178,7 @@ void EditTableDialog::populateConstraints()
const auto& constraint = pair.second;
// Columns
QTableWidgetItem* column = new QTableWidgetItem(columns.join(","));
QTableWidgetItem* column = new QTableWidgetItem(QString::fromStdString(sqlb::joinStringVector(columns, ",")));
column->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
ui->tableConstraints->setItem(row, kConstraintColumns, column);
@@ -207,12 +209,12 @@ void EditTableDialog::populateConstraints()
ui->tableConstraints->setCellWidget(row, kConstraintType, type);
// Name
QTableWidgetItem* name = new QTableWidgetItem(constraint->name());
QTableWidgetItem* name = new QTableWidgetItem(QString::fromStdString(constraint->name()));
name->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled /* TODO | Qt::ItemIsEditable */);
ui->tableConstraints->setItem(row, kConstraintName, name);
// SQL
QTableWidgetItem* sql = new QTableWidgetItem(constraint->toSql(columns));
QTableWidgetItem* sql = new QTableWidgetItem(QString::fromStdString(constraint->toSql(columns)));
name->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
ui->tableConstraints->setItem(row, kConstraintSql, sql);
@@ -229,7 +231,7 @@ void EditTableDialog::accept()
if(m_bNewTable)
{
// Creation of new table
if(!pdb.executeSQL(m_table.sql(ui->comboSchema->currentText())))
if(!pdb.executeSQL(QString::fromStdString(m_table.sql(ui->comboSchema->currentText().toStdString()))))
{
QMessageBox::warning(
this,
@@ -241,7 +243,7 @@ void EditTableDialog::accept()
// Editing of old table
// Apply all changes to the actual table in the database
if(!pdb.alterTable(curTable, m_table, trackColumns, ui->comboSchema->currentText()))
if(!pdb.alterTable(curTable, m_table, trackColumns, ui->comboSchema->currentText().toStdString()))
{
QMessageBox::warning(this, QApplication::applicationName(), pdb.lastError());
return;
@@ -261,21 +263,21 @@ void EditTableDialog::reject()
void EditTableDialog::updateSqlText()
{
ui->sqlTextEdit->setText(m_table.sql(ui->comboSchema->currentText()));
ui->sqlTextEdit->setText(QString::fromStdString(m_table.sql(ui->comboSchema->currentText().toStdString())));
}
void EditTableDialog::checkInput()
{
QString normTableName = ui->editTableName->text();
std::string normTableName = ui->editTableName->text().toStdString();
bool valid = true;
if(normTableName.isEmpty())
if(normTableName.empty())
valid = false;
if(ui->treeWidget->topLevelItemCount() == 0)
valid = false;
if (normTableName != m_table.name()) {
const QString oldTableName = m_table.name();
const std::string oldTableName = m_table.name();
m_table.setName(normTableName);
m_fkEditorDelegate->updateTablesList(oldTableName);
m_fkEditorDelegate->updateTablesList(QString::fromStdString(oldTableName));
// update fk's that refer to table itself recursively
const auto& fields = m_table.fields;
@@ -298,13 +300,13 @@ void EditTableDialog::updateTypes(QObject *object)
if(typeBox)
{
QString type = typeBox->currentText();
QString column = typeBox->property("column").toString();
std::string column = typeBox->property("column").toString().toStdString();
for(size_t index=0; index < m_table.fields.size(); ++index)
{
if(m_table.fields.at(index).name() == column)
{
m_table.fields.at(index).setType(type);
m_table.fields.at(index).setType(type.toStdString());
break;
}
}
@@ -333,7 +335,7 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
if(index < static_cast<int>(m_table.fields.size()))
{
sqlb::Field& field = m_table.fields.at(index);
QString oldFieldName = field.name();
QString oldFieldName = QString::fromStdString(field.name());
switch(column)
{
@@ -345,7 +347,7 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
// with different case. Example: if I rename column 'COLUMN' to 'column', findField() is going to return the current field number
// because it's doing a case-independent search and it can't return another field number because SQLite prohibits duplicate field
// names (no matter the case). So when this happens we just allow the renaming because there's no harm to be expected from it.
auto foundField = sqlb::findField(m_table, item->text(column));
auto foundField = sqlb::findField(m_table, item->text(column).toStdString());
if(foundField != m_table.fields.end() && foundField-m_table.fields.begin() != index)
{
QMessageBox::warning(this, qApp->applicationName(), tr("There already is a field with that name. Please rename it first or choose a different "
@@ -360,20 +362,20 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
// When editing an exiting table, check if any foreign keys would cause trouble in case this name is edited
if(!m_bNewTable)
{
QStringList pk = m_table.primaryKey();
sqlb::StringVector pk = m_table.primaryKey();
for(const sqlb::ObjectPtr& fkobj : pdb.schemata[curTable.schema()].values("table"))
{
auto fks = std::dynamic_pointer_cast<sqlb::Table>(fkobj)->constraints(QStringList(), sqlb::Constraint::ForeignKeyConstraintType);
auto fks = std::dynamic_pointer_cast<sqlb::Table>(fkobj)->constraints(sqlb::StringVector(), sqlb::Constraint::ForeignKeyConstraintType);
for(const sqlb::ConstraintPtr& fkptr : fks)
{
auto fk = std::dynamic_pointer_cast<sqlb::ForeignKeyClause>(fkptr);
if(fk->table() == m_table.name())
{
if(fk->columns().contains(field.name()) || contains(pk, field.name()))
if(contains(fk->columns(), field.name()) || contains(pk, field.name()))
{
QMessageBox::warning(this, qApp->applicationName(), tr("This column is referenced in a foreign key in table %1 and thus "
"its name cannot be changed.")
.arg(fkobj->name()));
.arg(QString::fromStdString(fkobj->name())));
// Reset the name to the old value but avoid calling this method again for that automatic change
ui->treeWidget->blockSignals(true);
item->setText(column, oldFieldName);
@@ -385,8 +387,8 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
}
}
field.setName(item->text(column));
m_table.renameKeyInAllConstraints(oldFieldName, item->text(column));
field.setName(item->text(column).toStdString());
m_table.renameKeyInAllConstraints(oldFieldName.toStdString(), item->text(column).toStdString());
qobject_cast<QComboBox*>(ui->treeWidget->itemWidget(item, kType))->setProperty("column", item->text(column));
// Update the field name in the map of old column names to new column names
@@ -395,7 +397,7 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
for(const auto& key : trackColumns.keys())
{
if(trackColumns[key] == oldFieldName)
trackColumns[key] = field.name();
trackColumns[key] = QString::fromStdString(field.name());
}
}
@@ -408,10 +410,10 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
case kPrimaryKey:
{
// Check if there already is a primary key
if(m_table.constraint(QStringList(), sqlb::Constraint::PrimaryKeyConstraintType))
if(m_table.constraint(sqlb::StringVector(), sqlb::Constraint::PrimaryKeyConstraintType))
{
// There already is a primary key for this table. So edit that one as there always can only be one primary key anyway.
QStringList& pk = m_table.primaryKeyRef();
sqlb::StringVector& pk = m_table.primaryKeyRef();
if(item->checkState(column) == Qt::Checked)
{
pk.push_back(field.name());
@@ -454,9 +456,9 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
// 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 coalesce(NULL,%3) IS NULL;")
.arg(sqlb::escapeIdentifier(pdb.getObjectByName<sqlb::Table>(curTable)->rowidColumns()).join(","))
.arg(curTable.toString())
.arg(sqlb::escapeIdentifier(field.name())));
.arg(QString::fromStdString(sqlb::joinStringVector(sqlb::escapeIdentifier(pdb.getObjectByName<sqlb::Table>(curTable)->rowidColumns()), ",")))
.arg(QString::fromStdString(curTable.toString()))
.arg(QString::fromStdString(sqlb::escapeIdentifier(field.name()))));
if(!m.completeCache())
{
// If we couldn't load all data because the cancel button was clicked, just unset the checkbox again and stop.
@@ -485,9 +487,9 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
{
SqliteTableModel m(pdb, this);
m.setQuery(QString("SELECT COUNT(*) FROM %1 WHERE %2 <> CAST(%3 AS INTEGER);")
.arg(curTable.toString())
.arg(sqlb::escapeIdentifier(field.name()))
.arg(sqlb::escapeIdentifier(field.name())));
.arg(QString::fromStdString(curTable.toString()))
.arg(QString::fromStdString(sqlb::escapeIdentifier(field.name())))
.arg(QString::fromStdString(sqlb::escapeIdentifier(field.name()))));
if(!m.completeCache())
{
// If we couldn't load all data because the cancel button was clicked, just unset the checkbox again and stop.
@@ -531,7 +533,7 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
{
// Because our renameColumn() function fails when setting a column to unique when it already contains the same values
SqliteTableModel m(pdb, this);
m.setQuery(QString("SELECT COUNT(%2) FROM %1;").arg(curTable.toString()).arg(sqlb::escapeIdentifier(field.name())));
m.setQuery(QString("SELECT COUNT(%2) FROM %1;").arg(QString::fromStdString(curTable.toString())).arg(QString::fromStdString(sqlb::escapeIdentifier(field.name()))));
if(!m.completeCache())
{
// If we couldn't load all data because the cancel button was clicked, just unset the checkbox again and stop.
@@ -539,7 +541,7 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
return;
}
int rowcount = m.data(m.index(0, 0)).toInt();
m.setQuery(QString("SELECT COUNT(DISTINCT %2) FROM %1;").arg(curTable.toString()).arg(sqlb::escapeIdentifier(field.name())));
m.setQuery(QString("SELECT COUNT(DISTINCT %2) FROM %1;").arg(QString::fromStdString(curTable.toString())).arg(QString::fromStdString(sqlb::escapeIdentifier(field.name()))));
if(!m.completeCache())
{
// If we couldn't load all data because the cancel button was clicked, just unset the checkbox again and stop.
@@ -550,7 +552,7 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
if(rowcount != uniquecount)
{
// There is a NULL value, so print an error message, uncheck the combobox, and return here
QMessageBox::information(this, qApp->applicationName(), tr("Column '%1' has duplicate data.\n").arg(field.name())
QMessageBox::information(this, qApp->applicationName(), tr("Column '%1' has duplicate data.\n").arg(QString::fromStdString(field.name()))
+ tr("This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled."));
item->setCheckState(column, Qt::Unchecked);
return;
@@ -586,11 +588,11 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
}
}
}
field.setDefaultValue(new_value);
field.setDefaultValue(new_value.toStdString());
}
break;
case kCheck:
field.setCheck(item->text(column));
field.setCheck(item->text(column).toStdString());
break;
case kForeignKey:
// handled in delegate
@@ -610,13 +612,13 @@ void EditTableDialog::addField()
// If this name happens to exist already, increase x by one until we find an unused name.
{
int field_number = ui->treeWidget->topLevelItemCount();
QString field_name;
std::string field_name;
do
{
field_name = "Field" + QString::number(field_number);
field_name = "Field" + std::to_string(field_number);
field_number++;
} while(sqlb::findField(m_table, field_name) != m_table.fields.end());
tbitem->setText(kName, field_name);
tbitem->setText(kName, QString::fromStdString(field_name));
}
QComboBox* typeBox = new QComboBox(ui->treeWidget);
@@ -645,7 +647,7 @@ void EditTableDialog::addField()
ui->treeWidget->editItem(tbitem, 0);
// add field to table object
m_table.fields.emplace_back(tbitem->text(kName), typeBox->currentText());
m_table.fields.emplace_back(tbitem->text(kName).toStdString(), typeBox->currentText().toStdString());
// Add the new column to the list of tracked columns to indicate it has been added
if(!m_bNewTable)
@@ -678,7 +680,7 @@ void EditTableDialog::removeField()
// Just delete that item. At this point there is no DB table to edit or data to be lost anyway
m_table.fields.erase(m_table.fields.begin() + ui->treeWidget->indexOfTopLevelItem(ui->treeWidget->currentItem()));
m_table.removeKeyFromAllConstraints(ui->treeWidget->currentItem()->text(kName));
m_table.removeKeyFromAllConstraints(ui->treeWidget->currentItem()->text(kName).toStdString());
delete ui->treeWidget->currentItem();
// Update the constraints view
+1
View File
@@ -4,6 +4,7 @@
#include "sql/sqlitetypes.h"
#include <QDialog>
#include <QMap>
class DBBrowserDB;
class QTreeWidgetItem;
+7 -7
View File
@@ -49,8 +49,8 @@ ExportDataDialog::ExportDataDialog(DBBrowserDB& db, ExportFormats format, QWidge
for(auto jt=tables.constBegin();jt!=tables.constEnd();++jt)
{
sqlb::ObjectIdentifier obj(it.key(), (*jt)->name());
QListWidgetItem* item = new QListWidgetItem(QIcon(QString(":icons/%1").arg(sqlb::Object::typeToString((*jt)->type()))), obj.toDisplayString());
item->setData(Qt::UserRole, obj.toVariant());
QListWidgetItem* item = new QListWidgetItem(QIcon(QString(":icons/%1").arg(QString::fromStdString(sqlb::Object::typeToString((*jt)->type())))), QString::fromStdString(obj.toDisplayString()));
item->setData(Qt::UserRole, QString::fromStdString(obj.toSerialised()));
ui->listTables->addItem(item);
}
}
@@ -63,7 +63,7 @@ ExportDataDialog::ExportDataDialog(DBBrowserDB& db, ExportFormats format, QWidge
} else {
for(int i=0;i<ui->listTables->count();i++)
{
if(sqlb::ObjectIdentifier(ui->listTables->item(i)->data(Qt::UserRole)) == selection)
if(sqlb::ObjectIdentifier(ui->listTables->item(i)->data(Qt::UserRole).toString().toStdString()) == selection)
{
ui->listTables->setCurrentRow(i);
break;
@@ -211,21 +211,21 @@ bool ExportDataDialog::exportQueryJson(const QString& sQuery, const QString& sFi
QApplication::setOverrideCursor(Qt::WaitCursor);
int columns = sqlite3_column_count(stmt);
size_t counter = 0;
QList<QString> column_names;
std::vector<std::string> column_names;
while(sqlite3_step(stmt) == SQLITE_ROW)
{
// Get column names if we didn't do so before
if(!column_names.size())
{
for(int i=0;i<columns;++i)
column_names.push_back(QString::fromUtf8(sqlite3_column_name(stmt, i)));
column_names.push_back(sqlite3_column_name(stmt, i));
}
json json_row;
for(int i=0;i<columns;++i)
{
int type = sqlite3_column_type(stmt, i);
std::string column_name = column_names[i].toStdString();
std::string column_name = column_names[i];
switch (type) {
case SQLITE_INTEGER: {
@@ -369,7 +369,7 @@ void ExportDataDialog::accept()
{
// if we are called from execute sql tab, query is already set
// and we only export 1 select
QString sQuery = QString("SELECT * FROM %1;").arg(sqlb::ObjectIdentifier(selectedItems.at(i)->data(Qt::UserRole)).toString());
QString sQuery = QString("SELECT * FROM %1;").arg(QString::fromStdString(sqlb::ObjectIdentifier(selectedItems.at(i)->data(Qt::UserRole).toString().toStdString()).toString()));
exportQuery(sQuery, filenames.at(i));
}
}
+1 -1
View File
@@ -30,7 +30,7 @@ ExportSqlDialog::ExportSqlDialog(DBBrowserDB* db, QWidget* parent, const QString
// Get list of tables to export
QList<sqlb::ObjectPtr> objects = pdb->schemata["main"].values("table");
for(const sqlb::ObjectPtr& it : objects)
ui->listTables->addItem(new QListWidgetItem(QIcon(QString(":icons/%1").arg(sqlb::Object::typeToString(it->type()))), it->name()));
ui->listTables->addItem(new QListWidgetItem(QIcon(QString(":icons/%1").arg(QString::fromStdString(sqlb::Object::typeToString(it->type())))), QString::fromStdString(it->name())));
// Sort list of tables and select the table specified in the
// selection parameter or all tables if table not specified
+6 -6
View File
@@ -136,16 +136,16 @@ QWidget* ExtendedTableWidgetEditorDelegate::createEditor(QWidget* parent, const
sqlb::ObjectIdentifier foreignTable = sqlb::ObjectIdentifier(m->currentTableName().schema(), fk.table());
QString column;
std::string column;
// If no column name is set, assume the primary key is meant
if(fk.columns().isEmpty()) {
if(fk.columns().empty()) {
sqlb::TablePtr obj = m->db().getObjectByName<sqlb::Table>(foreignTable);
column = obj->primaryKey().first();
column = obj->primaryKey().front();
} else
column = fk.columns().at(0);
sqlb::TablePtr currentTable = m->db().getObjectByName<sqlb::Table>(m->currentTableName());
QString query = QString("SELECT %1 FROM %2").arg(sqlb::escapeIdentifier(column)).arg(foreignTable.toString());
QString query = QString("SELECT %1 FROM %2").arg(QString::fromStdString(sqlb::escapeIdentifier(column))).arg(QString::fromStdString(foreignTable.toString()));
// if the current column of the current table does NOT have not-null constraint,
// the NULL is united to the query to get the possible values in the combo-box.
@@ -479,7 +479,7 @@ void ExtendedTableWidget::copyMimeData(const QModelIndexList& fromIndices, QMime
const QString rowSepText = "\n";
#endif
QString sqlInsertStatement = QString("INSERT INTO %1 (").arg(m->currentTableName().toString());
QString sqlInsertStatement = QString("INSERT INTO %1 (").arg(QString::fromStdString(m->currentTableName().toString()));
// Table headers
if (withHeaders || inSQL) {
htmlResult.append("<tr><th>");
@@ -861,7 +861,7 @@ void ExtendedTableWidget::cellClicked(const QModelIndex& index)
if(fk.isSet())
emit foreignKeyClicked(sqlb::ObjectIdentifier(m->currentTableName().schema(), fk.table()),
fk.columns().size() ? fk.columns().at(0) : "",
fk.columns().size() ? QString::fromStdString(fk.columns().at(0)) : "",
m->data(index, Qt::EditRole).toByteArray());
}
}
+2 -2
View File
@@ -6,11 +6,11 @@
#include <QMenu>
#include <QWhatsThis>
FilterLineEdit::FilterLineEdit(QWidget* parent, QList<FilterLineEdit*>* filters, int columnnum) : QLineEdit(parent), filterList(filters), columnNumber(columnnum)
FilterLineEdit::FilterLineEdit(QWidget* parent, std::vector<FilterLineEdit*>* filters, size_t columnnum) : QLineEdit(parent), filterList(filters), columnNumber(columnnum)
{
setPlaceholderText(tr("Filter"));
setClearButtonEnabled(true);
setProperty("column", columnnum); // Store the column number for later use
setProperty("column", static_cast<int>(columnnum)); // Store the column number for later use
// Introduce a timer for delaying the signal triggered whenever the user changes the filter value.
// The idea here is that the textChanged() event isn't connected to the update filter slot directly anymore
+4 -4
View File
@@ -2,7 +2,7 @@
#define FILTERLINEEDIT_H
#include <QLineEdit>
#include <QList>
#include <vector>
class QTimer;
class QKeyEvent;
@@ -12,7 +12,7 @@ class FilterLineEdit : public QLineEdit
Q_OBJECT
public:
explicit FilterLineEdit(QWidget* parent, QList<FilterLineEdit*>* filters, int columnnum);
explicit FilterLineEdit(QWidget* parent, std::vector<FilterLineEdit*>* filters, size_t columnnum);
// Override methods for programatically changing the value of the line edit
void clear();
@@ -32,8 +32,8 @@ protected:
void setFilterHelper(const QString& filterOperator, const QString& operatorSuffix = "");
private:
QList<FilterLineEdit*>* filterList;
int columnNumber;
std::vector<FilterLineEdit*>* filterList;
size_t columnNumber;
QTimer* delaySignalTimer;
QString lastValue;
+3 -3
View File
@@ -72,10 +72,10 @@ void FilterTableHeader::updateGeometries()
void FilterTableHeader::adjustPositions()
{
// Loop through all widgets
for(int i=0;i < filterWidgets.size(); ++i)
for(int i=0;i < static_cast<int>(filterWidgets.size()); ++i)
{
// Get the current widget, move it and resize it
QWidget* w = filterWidgets.at(i);
QWidget* w = filterWidgets.at(static_cast<size_t>(i));
// The two adds some extra space between the header label and the input widget
int y = QHeaderView::sizeHint().height() + 2;
if (QApplication::layoutDirection() == Qt::RightToLeft)
@@ -116,7 +116,7 @@ void FilterTableHeader::clearFilters()
filterLineEdit->clear();
}
void FilterTableHeader::setFilter(int column, const QString& value)
void FilterTableHeader::setFilter(size_t column, const QString& value)
{
if(column < filterWidgets.size())
filterWidgets.at(column)->setText(value);
+4 -4
View File
@@ -2,7 +2,7 @@
#define FILTERTABLEHEADER_H
#include <QHeaderView>
#include <QList>
#include <vector>
class QLineEdit;
class QTableView;
@@ -15,13 +15,13 @@ class FilterTableHeader : public QHeaderView
public:
explicit FilterTableHeader(QTableView* parent = nullptr);
QSize sizeHint() const override;
bool hasFilters() const {return (filterWidgets.count() > 0);}
bool hasFilters() const {return (filterWidgets.size() > 0);}
public slots:
void generateFilters(int number, bool showFirst = false);
void adjustPositions();
void clearFilters();
void setFilter(int column, const QString& value);
void setFilter(size_t column, const QString& value);
signals:
void filterChanged(int column, QString value);
@@ -39,7 +39,7 @@ private slots:
void editCondFormats();
private:
QList<FilterLineEdit*> filterWidgets;
std::vector<FilterLineEdit*> filterWidgets;
};
#endif
+12 -11
View File
@@ -87,7 +87,7 @@ ForeignKeyEditorDelegate::ForeignKeyEditorDelegate(const DBBrowserDB& db, sqlb::
{
if((*jt)->type() == sqlb::Object::Types::Table)
{
QString tableName = (*jt)->name();
QString tableName = QString::fromStdString((*jt)->name());
m_tablesIds.insert(tableName, std::dynamic_pointer_cast<sqlb::Table>(*jt)->fieldNames());
}
}
@@ -108,7 +108,8 @@ QWidget* ForeignKeyEditorDelegate::createEditor(QWidget* parent, const QStyleOpt
QComboBox* box = editor->idsComboBox;
box->clear();
box->addItem(QString()); // for those heroes who don't like to specify key explicitly
box->addItems(m_tablesIds[tableName]);
for(const auto& n : m_tablesIds[tableName])
box->addItem(QString::fromStdString(n));
box->setCurrentIndex(0);
});
@@ -126,10 +127,10 @@ void ForeignKeyEditorDelegate::setEditorData(QWidget* editor, const QModelIndex&
const sqlb::Field& field = m_table.fields.at(column);
auto fk = std::dynamic_pointer_cast<sqlb::ForeignKeyClause>(m_table.constraint({field.name()}, sqlb::Constraint::ForeignKeyConstraintType));
if (fk) {
fkEditor->tablesComboBox->setCurrentText(fk->table());
fkEditor->clauseEdit->setText(fk->constraint());
if (!fk->columns().isEmpty())
fkEditor->idsComboBox->setCurrentText(fk->columns().first());
fkEditor->tablesComboBox->setCurrentText(QString::fromStdString(fk->table()));
fkEditor->clauseEdit->setText(QString::fromStdString(fk->constraint()));
if (!fk->columns().empty())
fkEditor->idsComboBox->setCurrentText(QString::fromStdString(fk->columns().front()));
} else {
fkEditor->tablesComboBox->setCurrentIndex(-1);
}
@@ -150,16 +151,16 @@ void ForeignKeyEditorDelegate::setModelData(QWidget* editor, QAbstractItemModel*
sqlb::ForeignKeyClause* fk = new sqlb::ForeignKeyClause;
const QString table = fkEditor->tablesComboBox->currentText();
const QString id = fkEditor->idsComboBox->currentText();
const std::string id = fkEditor->idsComboBox->currentText().toStdString();
const QString clause = fkEditor->clauseEdit->text();
fk->setTable(table);
fk->setTable(table.toStdString());
if (!id.isEmpty())
if (!id.empty())
fk->setColumns({id});
if (!clause.trimmed().isEmpty()) {
fk->setConstraint(clause);
fk->setConstraint(clause.toStdString());
}
m_table.setConstraint({field.name()}, sqlb::ConstraintPtr(fk));
@@ -180,7 +181,7 @@ void ForeignKeyEditorDelegate::updateTablesList(const QString& oldTableName)
// this is used for recursive table constraints when
// table column references column within same table
m_tablesIds.remove(oldTableName);
m_tablesIds.insert(m_table.name(), m_table.fieldNames());
m_tablesIds.insert(QString::fromStdString(m_table.name()), m_table.fieldNames());
}
#include "ForeignKeyEditorDelegate.moc"
+3 -1
View File
@@ -2,6 +2,8 @@
#define FOREIGNKEYDELEGATE_H
#include <QStyledItemDelegate>
#include <vector>
#include <string>
class DBBrowserDB;
class QPushButton;
@@ -30,7 +32,7 @@ public:
private:
const DBBrowserDB& m_db;
sqlb::Table& m_table;
mutable QMap<QString, QStringList> m_tablesIds;
mutable QMap<QString, std::vector<std::string>> m_tablesIds;
};
#endif // FOREIGNKEYDELEGATE_H
+13 -13
View File
@@ -245,7 +245,7 @@ void ImportCsvDialog::updatePreview()
// Set horizontal header data
QStringList horizontalHeader;
for(const sqlb::Field& field : fieldList)
horizontalHeader.push_back(field.name());
horizontalHeader.push_back(QString::fromStdString(field.name()));
ui->tablePreview->setHorizontalHeaderLabels(horizontalHeader);
// Parse file
@@ -416,7 +416,7 @@ sqlb::FieldVector ImportCsvDialog::generateFieldList(const QString& filename)
// Add field to the column list. For now we set the data type to nothing but this might be overwritten later in the automatic
// type detection code.
fieldList.emplace_back(fieldname, "");
fieldList.emplace_back(fieldname.toStdString(), "");
}
// Try to find out a data type for each column. Skip the header row if there is one.
@@ -426,7 +426,7 @@ sqlb::FieldVector ImportCsvDialog::generateFieldList(const QString& filename)
{
// If the data type has been set to TEXT, there's no going back because it means we had at least one row with text-only
// content and that means we don't want to set the data type to any number type.
QString old_type = fieldList.at(i).type();
std::string old_type = fieldList.at(i).type();
if(old_type != "TEXT")
{
QString content = QString::fromUtf8(data.fields[i].data, data.fields[i].data_length);
@@ -437,7 +437,7 @@ sqlb::FieldVector ImportCsvDialog::generateFieldList(const QString& filename)
content.toFloat(&convert_to_float);
// Set new data type. If we don't find any better data type, we fall back to the TEXT data type
QString new_type = "TEXT";
std::string new_type = "TEXT";
if(old_type == "INTEGER" && !convert_to_int && convert_to_float) // So far it's integer, but now it's only convertible to float
new_type = "REAL";
else if(old_type == "" && convert_to_int) // No type yet, but this bit is convertible to integer
@@ -497,7 +497,7 @@ bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name)
// Are we importing into an existing table?
bool importToExistingTable = false;
const sqlb::ObjectPtr obj = pdb->getObjectByName(sqlb::ObjectIdentifier("main", tableName));
const sqlb::ObjectPtr obj = pdb->getObjectByName(sqlb::ObjectIdentifier("main", tableName.toStdString()));
if(obj && obj->type() == sqlb::Object::Types::Table)
{
if(std::dynamic_pointer_cast<sqlb::Table>(obj)->fields.size() != fieldList.size())
@@ -542,13 +542,13 @@ bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name)
}
// Create table
QVector<QByteArray> nullValues;
std::vector<QByteArray> nullValues;
std::vector<bool> failOnMissingFieldList;
bool ignoreDefaults = ui->checkIgnoreDefaults->isChecked();
bool failOnMissing = ui->checkFailOnMissing->isChecked();
if(!importToExistingTable)
{
if(!pdb->createTable(sqlb::ObjectIdentifier("main", tableName), fieldList))
if(!pdb->createTable(sqlb::ObjectIdentifier("main", tableName.toStdString()), fieldList))
{
rollback(this, pdb, nullptr, restorepointName, 0, tr("Creating the table failed: %1").arg(pdb->lastError()));
return false;
@@ -562,7 +562,7 @@ bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name)
// 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<sqlb::Table>(sqlb::ObjectIdentifier("main", tableName));
sqlb::TablePtr tbl = pdb->getObjectByName<sqlb::Table>(sqlb::ObjectIdentifier("main", tableName.toStdString()));
if(tbl)
{
for(const sqlb::Field& f : tbl->fields)
@@ -575,9 +575,9 @@ bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name)
// If a field has a default value, that gets priority over everything else.
// Exception: if the user wants to ignore default values we never use them.
if(!ignoreDefaults && !f.defaultValue().isNull())
if(!ignoreDefaults && !f.defaultValue().empty())
{
nullValues << f.defaultValue().toUtf8();
nullValues.push_back(f.defaultValue().c_str());
} else {
// If it has no default value, check if the field is NOT NULL
if(f.notnull())
@@ -586,9 +586,9 @@ bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name)
// If this is an integer column insert 0. Otherwise insert an empty string.
if(f.isInteger())
nullValues << "0";
nullValues.push_back("0");
else
nullValues << "";
nullValues.push_back("");
// If the user wants to fail the import, remember this field
if(failOnMissing)
@@ -597,7 +597,7 @@ bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name)
// The field is not NOT NULL (stupid double negation here! NULL values are allowed in this case)
// Just insert a NULL value
nullValues << QByteArray();
nullValues.push_back(QByteArray());
}
}
}
+51 -43
View File
@@ -76,10 +76,15 @@ QDataStream& operator>>(QDataStream& ds, sqlb::ObjectIdentifier& objid)
// If it is a string list, we can treat it as an object identifier. If it isn't, we assume it's just a
// single string and use interpret it as the table name in the main schema. This is done for backwards
// compatability with old project file formats.
if(v.toStringList().isEmpty())
objid = sqlb::ObjectIdentifier("main", v.toString());
else
objid = sqlb::ObjectIdentifier(v);
QStringList str = v.toStringList();
if(str.isEmpty())
{
objid = sqlb::ObjectIdentifier("main", v.toString().toStdString());
} else {
objid.setSchema(str.first().toStdString());
if(str.size() >= 2)
objid.setName(str.last().toStdString());
}
return ds;
}
@@ -662,13 +667,13 @@ void MainWindow::populateStructure(const QString& old_table)
objectMap tab = db.getBrowsableObjects(it.key());
for(auto jt : tab)
{
QString objectname = jt->name();
QString objectname = QString::fromStdString(jt->name());
sqlb::FieldInfoList fi = jt->fieldInformation();
for(const sqlb::FieldInfo& f : fi)
tablesToColumnsMap[objectname].append(f.name);
tablesToColumnsMap[objectname].append(QString::fromStdString(f.name));
}
qualifiedTablesMap[it.key()] = tablesToColumnsMap;
qualifiedTablesMap[QString::fromStdString(it.key())] = tablesToColumnsMap;
}
SqlTextEdit::sqlLexer->setTableNames(qualifiedTablesMap);
ui->editLogApplication->reloadKeywords();
@@ -798,7 +803,6 @@ void MainWindow::populateTable()
query.where().insert({it.key(), CondFormat::filterToSqlCondition(it.value(), m_browseTableModel->encoding()).toStdString()});
// Display formats
QVector<QString> v;
bool only_defaults = true;
if(db.getObjectByName(tablename))
{
@@ -808,10 +812,10 @@ void MainWindow::populateTable()
QString format = storedData.displayFormats[i+1];
if(format.size())
{
query.selectedColumns().emplace_back(tablefields.at(i).name.toStdString(), format.toStdString());
query.selectedColumns().emplace_back(tablefields.at(i).name, format.toStdString());
only_defaults = false;
} else {
query.selectedColumns().emplace_back(tablefields.at(i).name.toStdString(), tablefields.at(i).name.toStdString());
query.selectedColumns().emplace_back(tablefields.at(i).name, tablefields.at(i).name);
}
}
}
@@ -1206,8 +1210,8 @@ void MainWindow::compact()
void MainWindow::deleteObject()
{
// Get name and type of object to delete
sqlb::ObjectIdentifier name(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString(),
ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString());
sqlb::ObjectIdentifier name(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString(),
ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString());
QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString();
// Due to different grammar in languages (e.g. gender or declension), each message must be given separately to translation.
@@ -1222,11 +1226,11 @@ void MainWindow::deleteObject()
message = tr("Are you sure you want to delete the index '%1'?");
// Ask user if he really wants to delete that table
if(QMessageBox::warning(this, QApplication::applicationName(), message.arg(name.name()),
if(QMessageBox::warning(this, QApplication::applicationName(), message.arg(QString::fromStdString(name.name())),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)
{
// Delete the table
QString statement = QString("DROP %1 %2;").arg(type.toUpper()).arg(name.toString());
QString statement = QString("DROP %1 %2;").arg(type.toUpper()).arg(QString::fromStdString(name.toString()));
if(!db.executeSQL(statement))
{
if (type == "table")
@@ -1253,8 +1257,8 @@ void MainWindow::editObject()
return;
// Get name and type of the object to edit
sqlb::ObjectIdentifier name(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString(),
ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString());
sqlb::ObjectIdentifier name(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString(),
ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString());
QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString();
if(type == "table")
@@ -1281,7 +1285,7 @@ void MainWindow::editObject()
// If foreign_keys were enabled, we must commit or rollback the transaction so the foreign_keys pragma can be restored.
if (foreign_keys == "1") {
if (!db.querySingleValueFromDb(QString("PRAGMA %1.foreign_key_check").arg(sqlb::escapeIdentifier(name.schema()))).isNull()) {
if (!db.querySingleValueFromDb(QString("PRAGMA %1.foreign_key_check").arg(QString::fromStdString(sqlb::escapeIdentifier(name.schema())))).isNull()) {
// Raise warning for accepted modification. When rejected, warn user also since we know now that the table has problems,
// but it wasn't our fault.
if (ok)
@@ -1661,7 +1665,7 @@ void MainWindow::exportTableToCSV()
{
QString schema = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema)).toString();
QString name = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName)).toString();
current_table = sqlb::ObjectIdentifier(schema, name);
current_table = sqlb::ObjectIdentifier(schema.toStdString(), name.toStdString());
}
} else if(ui->mainTab->currentWidget() == ui->browser) {
current_table = currentlyBrowsedTableName();
@@ -1683,7 +1687,7 @@ void MainWindow::exportTableToJson()
{
QString schema = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema)).toString();
QString name = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName)).toString();
current_table = sqlb::ObjectIdentifier(schema, name);
current_table = sqlb::ObjectIdentifier(schema.toStdString(), name.toStdString());
}
} else if(ui->mainTab->currentWidget() == ui->browser) {
current_table = currentlyBrowsedTableName();
@@ -2062,7 +2066,7 @@ void MainWindow::browseTableHeaderClicked(int logicalindex)
// If the last sort column was just clicked again, change its sort order.
// If not, add the column as a new sort column to the list.
if(columns.size() && columns.back().column == logicalindex)
if(columns.size() && columns.back().column == static_cast<size_t>(logicalindex))
columns.back().direction = (columns.back().direction == sqlb::Ascending ? sqlb::Descending : sqlb::Ascending);
else
columns.emplace_back(logicalindex, sqlb::Ascending);
@@ -2071,7 +2075,7 @@ void MainWindow::browseTableHeaderClicked(int logicalindex)
// If we have exactly one sort column and it is the column which was just clicked, change its sort order.
// If not, clear the list of sorting columns and replace it by a single new sort column.
if(columns.size() == 1 && columns.front().column == logicalindex)
if(columns.size() == 1 && columns.front().column == static_cast<size_t>(logicalindex))
{
columns.front().direction = (columns.front().direction == sqlb::Ascending ? sqlb::Descending : sqlb::Ascending);
} else {
@@ -2694,7 +2698,7 @@ static void loadBrowseDataTableSettings(BrowseDataTableSettings& settings, QXmlS
QColor(xml.attributes().value("foreground").toString()),
QColor(xml.attributes().value("background").toString()),
settings.encoding);
settings.condFormats[index].append(newCondFormat);
settings.condFormats[index].push_back(newCondFormat);
xml.skipCurrentElement();
}
}
@@ -2887,8 +2891,8 @@ bool MainWindow::loadProject(QString filename, bool readOnly)
if (xml.name() == "table") {
sqlb::ObjectIdentifier tableIdentifier =
sqlb::ObjectIdentifier (xml.attributes().value("schema").toString(),
xml.attributes().value("name").toString());
sqlb::ObjectIdentifier (xml.attributes().value("schema").toString().toStdString(),
xml.attributes().value("name").toString().toStdString());
BrowseDataTableSettings settings;
loadBrowseDataTableSettings(settings, xml);
browseTableSettings[tableIdentifier] = settings;
@@ -3138,8 +3142,8 @@ QString MainWindow::saveProject(const QString& currentFilename)
for(auto tableIt=browseTableSettings.constBegin(); tableIt!=browseTableSettings.constEnd(); ++tableIt) {
xml.writeStartElement("table");
xml.writeAttribute("schema", tableIt.key().schema());
xml.writeAttribute("name", tableIt.key().name());
xml.writeAttribute("schema", QString::fromStdString(tableIt.key().schema()));
xml.writeAttribute("name", QString::fromStdString(tableIt.key().name()));
saveBrowseDataTableSettings(tableIt.value(), xml);
xml.writeEndElement();
}
@@ -3226,12 +3230,12 @@ void MainWindow::addCondFormat(int column, const QString& value)
m_condFormatPalette.nextSerialColor(Palette::appHasDarkTheme()),
m_browseTableModel->encoding());
m_browseTableModel->addCondFormat(column, newCondFormat);
browseTableSettings[currentlyBrowsedTableName()].condFormats[column].append(newCondFormat);
browseTableSettings[currentlyBrowsedTableName()].condFormats[column].push_back(newCondFormat);
}
void MainWindow::clearAllCondFormats(int column)
{
QVector<CondFormat> emptyCondFormatVector = QVector<CondFormat>();
std::vector<CondFormat> emptyCondFormatVector = std::vector<CondFormat>();
m_browseTableModel->setCondFormats(column, emptyCondFormatVector);
browseTableSettings[currentlyBrowsedTableName()].condFormats[column].clear();
isProjectModified = true;
@@ -3242,7 +3246,7 @@ void MainWindow::editCondFormats(int column)
CondFormatManager condFormatDialog(browseTableSettings[currentlyBrowsedTableName()].condFormats[column],
m_browseTableModel->encoding(), this);
if (condFormatDialog.exec()) {
QVector<CondFormat> condFormatVector = condFormatDialog.getCondFormats();
std::vector<CondFormat> condFormatVector = condFormatDialog.getCondFormats();
m_browseTableModel->setCondFormats(column, condFormatVector);
browseTableSettings[currentlyBrowsedTableName()].condFormats[column] = condFormatVector;
isProjectModified = true;
@@ -3334,9 +3338,9 @@ void MainWindow::switchToBrowseDataTab(QString tableToBrowse)
if(!ui->dbTreeWidget->selectionModel()->hasSelection())
return;
sqlb::ObjectIdentifier obj(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema)).toString(),
ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName)).toString());
tableToBrowse = obj.toDisplayString();
sqlb::ObjectIdentifier obj(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema)).toString().toStdString(),
ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName)).toString().toStdString());
tableToBrowse = QString::fromStdString(obj.toDisplayString());
}
ui->comboBrowseTable->setCurrentIndex(ui->comboBrowseTable->findText(tableToBrowse));
@@ -3372,15 +3376,15 @@ void MainWindow::jumpToRow(const sqlb::ObjectIdentifier& table, QString column,
// If no column name is set, assume the primary key is meant
if(!column.size())
column = obj->primaryKey().first();
column = QString::fromStdString(obj->primaryKey().front());
// If column doesn't exist don't do anything
auto column_index = sqlb::findField(obj, column);
auto column_index = sqlb::findField(obj, column.toStdString());
if(column_index == obj->fields.end())
return;
// Jump to table
ui->comboBrowseTable->setCurrentIndex(ui->comboBrowseTable->findText(table.toDisplayString()));
ui->comboBrowseTable->setCurrentIndex(ui->comboBrowseTable->findText(QString::fromStdString(table.toDisplayString())));
populateTable();
// Set filter
@@ -3456,9 +3460,9 @@ void MainWindow::editDataColumnDisplayFormat()
int field_number = sender()->property("clicked_column").toInt();
QString field_name;
if (db.getObjectByName(current_table)->type() == sqlb::Object::Table)
field_name = db.getObjectByName<sqlb::Table>(current_table)->fields.at(field_number-1).name();
field_name = QString::fromStdString(db.getObjectByName<sqlb::Table>(current_table)->fields.at(field_number-1).name());
else
field_name = db.getObjectByName<sqlb::View>(current_table)->fieldNames().at(field_number-1);
field_name = QString::fromStdString(db.getObjectByName<sqlb::View>(current_table)->fieldNames().at(field_number-1));
// Get the current display format of the field
QString current_displayformat = browseTableSettings[current_table].displayFormats[field_number];
@@ -3600,12 +3604,16 @@ void MainWindow::unlockViewEditing(bool unlock, QString pk)
{
bool ok;
QStringList options;
for(const auto& n : obj->fieldNames())
options.push_back(QString::fromStdString(n));
// Ask for a PK
pk = QInputDialog::getItem(this,
qApp->applicationName(),
tr("Please enter a pseudo-primary key in order to enable editing on this view. "
"This should be the name of a unique column in the view."),
obj->fieldNames(),
options,
0,
false,
&ok);
@@ -3617,7 +3625,7 @@ void MainWindow::unlockViewEditing(bool unlock, QString pk)
}
// Do some basic testing of the input and if the input appears to be good, go on
if(db.executeSQL(QString("SELECT %1 FROM %2 LIMIT 1;").arg(sqlb::escapeIdentifier(pk)).arg(currentTable.toString()), false, true))
if(db.executeSQL(QString("SELECT %1 FROM %2 LIMIT 1;").arg(sqlb::escapeIdentifier(pk)).arg(QString::fromStdString(currentTable.toString())), false, true))
break;
}
} else if(!unlock) {
@@ -3651,9 +3659,9 @@ sqlb::ObjectIdentifier MainWindow::currentlyBrowsedTableName() const
{
return sqlb::ObjectIdentifier(ui->comboBrowseTable->model()->data(dbStructureModel->index(ui->comboBrowseTable->currentIndex(),
DbStructureModel::ColumnSchema,
ui->comboBrowseTable->rootModelIndex())).toString(),
ui->comboBrowseTable->currentData(Qt::EditRole).toString()); // Use the edit role here to make sure we actually get the
// table name without the schema bit in front of it.
ui->comboBrowseTable->rootModelIndex())).toString().toStdString(),
ui->comboBrowseTable->currentData(Qt::EditRole).toString().toStdString()); // Use the edit role here to make sure we actually get the
// table name without the schema bit in front of it.
}
void MainWindow::hideColumns(int column, bool hide)
@@ -3780,7 +3788,7 @@ void MainWindow::saveAsView(QString query)
name = QInputDialog::getText(this, qApp->applicationName(), tr("Please specify the view name")).trimmed();
if(name.isNull())
return;
if(db.getObjectByName(sqlb::ObjectIdentifier("main", name)) != nullptr)
if(db.getObjectByName(sqlb::ObjectIdentifier("main", name.toStdString())) != nullptr)
QMessageBox::warning(this, qApp->applicationName(), tr("There is already an object with that name. Please choose a different name."));
else
break;
+1 -1
View File
@@ -36,7 +36,7 @@ struct BrowseDataTableSettings
sqlb::Query query; // NOTE: We only store the sort order in here (for now)
QMap<int, int> columnWidths;
QMap<int, QString> filterValues;
QMap<int, QVector<CondFormat>> condFormats;
QMap<int, std::vector<CondFormat>> condFormats;
QMap<int, QString> displayFormats;
bool showRowid;
QString encoding;
-1
View File
@@ -3,7 +3,6 @@
#include <QDialog>
#include <QVariant>
#include <QHash>
class QTreeWidgetItem;
class QFrame;
+1 -1
View File
@@ -99,7 +99,7 @@ private:
// Pointer to the root item. This contains all the actual item data.
RemoteModelItem* rootItem;
// Thr header list is a list of column titles. It's a static list that's getting filled in the constructor.
// The header list is a list of column titles. It's a static list that's getting filled in the constructor.
QStringList headerList;
// Reference to the remote database object which is stored somewhere in the main window.
+5 -5
View File
@@ -19,7 +19,7 @@ namespace {
RowLoader::RowLoader (
std::function<std::shared_ptr<sqlite3>(void)> db_getter_,
std::function<void(QString)> statement_logger_,
QStringList & headers_,
std::vector<std::string> & headers_,
QMutex & cache_mutex_,
Cache & cache_data_
)
@@ -230,7 +230,7 @@ void RowLoader::process (Task & t)
if(SQLITE_OK == status)
{
const int num_columns = headers.size();
const int num_columns = static_cast<int>(headers.size());
while(!t.cancel && sqlite3_step(stmt) == SQLITE_ROW)
{
@@ -239,13 +239,13 @@ void RowLoader::process (Task & t)
{
if(sqlite3_column_type(stmt, i) == SQLITE_NULL)
{
rowdata.append(QByteArray());
rowdata.push_back(QByteArray());
} else {
int bytes = sqlite3_column_bytes(stmt, i);
if(bytes)
rowdata.append(QByteArray(static_cast<const char*>(sqlite3_column_blob(stmt, i)), bytes));
rowdata.push_back(QByteArray(static_cast<const char*>(sqlite3_column_blob(stmt, i)), bytes));
else
rowdata.append(QByteArray(""));
rowdata.push_back(QByteArray(""));
}
}
QMutexLocker lk(&cache_mutex);
+4 -4
View File
@@ -7,10 +7,10 @@
#include <memory>
#include <future>
#include <functional>
#include <vector>
#include <QThread>
#include <QString>
#include <QStringList>
#include <QMutex>
#include "sqlite.h"
@@ -23,13 +23,13 @@ class RowLoader : public QThread
void run() override;
public:
typedef RowCache<QVector<QByteArray>> Cache;
typedef RowCache<std::vector<QByteArray>> Cache;
/// set up worker thread to handle row loading
explicit RowLoader (
std::function<std::shared_ptr<sqlite3>(void)> db_getter,
std::function<void(QString)> statement_logger,
QStringList & headers,
std::vector<std::string> & headers,
QMutex & cache_mutex,
Cache & cache_data
);
@@ -69,7 +69,7 @@ signals:
private:
const std::function<std::shared_ptr<sqlite3>()> db_getter;
const std::function<void(QString)> statement_logger;
QStringList & headers;
std::vector<std::string> & headers;
QMutex & cache_mutex;
Cache & cache_data;
+1 -1
View File
@@ -3,7 +3,7 @@
#include "SqlUiLexer.h"
#include "Qsci/qsciapis.h"
#include "Settings.h"
#include "sql/sqlitetypes.h"
#include "sqlitedb.h"
SqlUiLexer::SqlUiLexer(QObject* parent) :
QsciLexerSQL(parent)
+1 -1
View File
@@ -19,7 +19,7 @@ VacuumDialog::VacuumDialog(DBBrowserDB* _db, QWidget* parent) :
for(auto it=db->schemata.constBegin();it!=db->schemata.constEnd();++it)
{
QTreeWidgetItem* item = new QTreeWidgetItem(ui->treeDatabases);
item->setText(0, it.key());
item->setText(0, QString::fromStdString(it.key()));
item->setIcon(0, QIcon(QString(":icons/database")));
ui->treeDatabases->addTopLevelItem(item);
}
+2 -2
View File
@@ -87,13 +87,13 @@ std::string Query::buildQuery(bool withRowid) const
order_by = "ORDER BY " + order_by;
}
return "SELECT " + selector + " FROM " + m_table.toString().toStdString() + " " + where + " " + order_by;
return "SELECT " + selector + " FROM " + m_table.toString() + " " + where + " " + order_by;
}
std::string Query::buildCountQuery() const
{
// Build simplest count query for this (filtered) table
return "SELECT COUNT(*) FROM " + m_table.toString().toStdString() + " " + buildWherePart();
return "SELECT COUNT(*) FROM " + m_table.toString() + " " + buildWherePart();
}
std::vector<SelectedColumn>::iterator Query::findSelectedColumnByName(const std::string& name)
+186 -197
View File
@@ -5,6 +5,8 @@
#include <sstream>
#include <iostream>
#include <clocale> // This include seems to only be necessary for the Windows build
#include <regex>
#include <numeric>
namespace sqlb {
@@ -15,11 +17,11 @@ void setIdentifierQuoting(escapeQuoting toQuoting)
customQuoting = toQuoting;
}
QString escapeIdentifier(QString id)
std::string escapeIdentifier(std::string id)
{
switch(customQuoting) {
case GraveAccents:
return '`' + id.replace('`', "``") + '`';
return '`' + std::regex_replace(id, std::regex("\\`"), "``") + '`';
case SquareBrackets:
// There aren't any escaping possibilities for square brackets inside the identifier,
// so we rely on the user to not enter these characters when this kind of quoting is
@@ -30,23 +32,25 @@ QString escapeIdentifier(QString id)
// This may produce a 'control reaches end of non-void function' warning if the
// default branch is removed, even though we have covered all possibilities in the
// switch statement.
return '"' + id.replace('"', "\"\"") + '"';
return '"' + std::regex_replace(id, std::regex("\\\""), "\"\"") + '"';
}
}
std::string escapeIdentifier(std::string id)
StringVector escapeIdentifier(StringVector ids)
{
return escapeIdentifier(QString::fromStdString(id)).toStdString();
}
QStringList escapeIdentifier(QStringList ids)
{
std::transform(ids.begin(), ids.end(), ids.begin(), [](const QString& id) {
std::transform(ids.begin(), ids.end(), ids.begin(), [](const std::string& id) {
return escapeIdentifier(id);
});
return ids;
}
std::string joinStringVector(const StringVector& vec, const std::string& delim)
{
return std::accumulate(vec.begin(), vec.end(), std::string(), [delim](const std::string& so_far, const std::string& s) {
return so_far.empty() ? s : so_far + delim + s;
});
}
/**
* @brief The SetLocaleToC class
* This is a stupid helper class which sets the current locale as used by the C++ standard library to the C locale.
@@ -91,7 +95,7 @@ public:
private:
void parsecolumn(Table* table, antlr::RefAST c);
QString parseConflictClause(antlr::RefAST c);
std::string parseConflictClause(antlr::RefAST c);
private:
antlr::RefAST m_root;
@@ -130,7 +134,7 @@ bool Object::operator==(const Object& rhs) const
return true;
}
QString Object::typeToString(Types type)
std::string Object::typeToString(Types type)
{
switch(type)
{
@@ -139,7 +143,7 @@ QString Object::typeToString(Types type)
case Types::View: return "view";
case Types::Trigger: return "trigger";
}
return QString();
return "";
}
bool ForeignKeyClause::isSet() const
@@ -147,18 +151,18 @@ bool ForeignKeyClause::isSet() const
return m_override.size() || m_table.size();
}
QString ForeignKeyClause::toString() const
std::string ForeignKeyClause::toString() const
{
if(!isSet())
return QString();
return "";
if(m_override.size())
return m_override;
QString result = escapeIdentifier(m_table);
std::string result = escapeIdentifier(m_table);
if(m_columns.size())
result += "(" + escapeIdentifier(m_columns).join(",") + ")";
result += "(" + joinStringVector(escapeIdentifier(m_columns), ",") + ")";
if(m_constraint.size())
result += " " + m_constraint;
@@ -166,50 +170,50 @@ QString ForeignKeyClause::toString() const
return result;
}
void ForeignKeyClause::setFromString(const QString& fk)
void ForeignKeyClause::setFromString(const std::string& fk)
{
m_override = fk;
}
QString ForeignKeyClause::toSql(const QStringList& applyOn) const
std::string ForeignKeyClause::toSql(const StringVector& applyOn) const
{
QString result;
if(!m_name.isNull())
result += QString("CONSTRAINT %1 ").arg(escapeIdentifier(m_name));
result += QString("FOREIGN KEY(%1) REFERENCES %2").arg(escapeIdentifier(applyOn).join(",")).arg(this->toString());
std::string result;
if(!m_name.empty())
result = "CONSTRAINT " + escapeIdentifier(m_name) + " ";
result += "FOREIGN KEY(" + joinStringVector(escapeIdentifier(applyOn), ",") + ") REFERENCES " + this->toString();
return result;
}
QString UniqueConstraint::toSql(const QStringList& applyOn) const
std::string UniqueConstraint::toSql(const StringVector& applyOn) const
{
QString result;
if(!m_name.isNull())
result += QString("CONSTRAINT %1 ").arg(escapeIdentifier(m_name));
result += QString("UNIQUE(%1)").arg(escapeIdentifier(applyOn).join(","));
std::string result;
if(!m_name.empty())
result = "CONSTRAINT " + escapeIdentifier(m_name) + " ";
result += "UNIQUE(" + joinStringVector(escapeIdentifier(applyOn), ",") + ")";
return result;
}
QString PrimaryKeyConstraint::toSql(const QStringList& applyOn) const
std::string PrimaryKeyConstraint::toSql(const StringVector& applyOn) const
{
QString result;
if(!m_name.isNull())
result += QString("CONSTRAINT %1 ").arg(escapeIdentifier(m_name));
result += QString("PRIMARY KEY(%1)").arg(escapeIdentifier(applyOn).join(","));
std::string result;
if(!m_name.empty())
result = "CONSTRAINT " + escapeIdentifier(m_name) + " ";
result += "PRIMARY KEY(" + joinStringVector(escapeIdentifier(applyOn), ",") + ")";
if(!m_conflictAction.isEmpty())
if(!m_conflictAction.empty())
result += " ON CONFLICT " + m_conflictAction;
return result;
}
QString CheckConstraint::toSql(const QStringList&) const
std::string CheckConstraint::toSql(const StringVector&) const
{
QString result;
if(!m_name.isNull())
result += QString("CONSTRAINT %1 ").arg(escapeIdentifier(m_name));
result += QString("CHECK(%1)").arg(m_expression);
std::string result;
if(!m_name.empty())
result = "CONSTRAINT " + escapeIdentifier(m_name) + " ";
result += "CHECK(" + m_expression + ")";
return result;
}
@@ -236,83 +240,55 @@ bool Field::operator==(const Field& rhs) const
return true;
}
QString Field::toString(const QString& indent, const QString& sep) const
std::string Field::toString(const std::string& indent, const std::string& sep) const
{
QString str = indent + escapeIdentifier(m_name) + sep + m_type;
std::string str = indent + escapeIdentifier(m_name) + sep + m_type;
if(m_notnull)
str += " NOT NULL";
if(!m_defaultvalue.isEmpty())
str += QString(" DEFAULT %1").arg(m_defaultvalue);
if(!m_check.isEmpty())
if(!m_defaultvalue.empty())
str += " DEFAULT " + m_defaultvalue;
if(!m_check.empty())
str += " CHECK(" + m_check + ")";
if(m_autoincrement)
str += " PRIMARY KEY AUTOINCREMENT";
if(m_unique)
str += " UNIQUE";
if(!m_collation.isEmpty())
if(!m_collation.empty())
str += " COLLATE " + m_collation;
return str;
}
bool Field::isText() const
{
QString norm = m_type.trimmed().toLower();
return norm.startsWith("character")
|| norm.startsWith("varchar")
|| norm.startsWith("varying character")
|| norm.startsWith("nchar")
|| norm.startsWith("native character")
|| norm.startsWith("nvarchar")
|| norm == "text"
|| norm == "clob";
std::regex is_text("(^(character|varchar|varying character|nchar|native character|nvarchar))|(^(text|clob)$)", std::regex::icase);
return std::regex_match(m_type, is_text);
}
bool Field::isInteger() const
{
QString norm = m_type.trimmed().toLower();
return norm == "int"
|| norm == "integer"
|| norm == "tinyint"
|| norm == "smallint"
|| norm == "mediumint"
|| norm == "bigint"
|| norm == "unsigned big int"
|| norm == "int2"
|| norm == "int8";
std::regex is_integer("^(int|integer|tinyint|smallint|mediumint|bigint|unsigned big int|int2|int8)$", std::regex::icase);
return std::regex_match(m_type, is_integer);
}
bool Field::isReal() const
{
QString norm = m_type.trimmed().toLower();
return norm == "real"
|| norm == "double"
|| norm == "double precision"
|| norm == "float";
std::regex is_real("^(real|double|double precision|float)$", std::regex::icase);
return std::regex_match(m_type, is_real);
}
bool Field::isNumeric() const
{
QString norm = m_type.trimmed().toLower();
return norm.startsWith("decimal")
|| norm == "numeric"
|| norm == "boolean"
|| norm == "date"
|| norm == "datetime";
std::regex is_numeric("(^(decimal))|(^(numeric|boolean|date|datetime)$)", std::regex::icase);
return std::regex_match(m_type, is_numeric);
}
bool Field::isBlob() const
{
QString norm = m_type.trimmed().toLower();
return norm.isEmpty()
|| norm == "blob";
std::regex is_blob("(^$)|(^blob$)", std::regex::icase);
return std::regex_match(m_type, is_blob);
}
QString Field::affinity() const
std::string Field::affinity() const
{
if (isInteger()) return "INTEGER";
@@ -386,27 +362,27 @@ bool Table::operator==(const Table& rhs) const
return true;
}
QStringList Table::fieldList() const
StringVector Table::fieldList() const
{
QStringList sl;
StringVector sl;
for(const Field& f : fields)
sl << f.toString();
sl.push_back(f.toString());
return sl;
}
QStringList Table::fieldNames() const
StringVector Table::fieldNames() const
{
QStringList sl;
StringVector sl;
for(const Field& f : fields)
sl << f.name();
sl.push_back(f.name());
return sl;
}
QStringList Table::rowidColumns() const
StringVector Table::rowidColumns() const
{
// For WITHOUT ROWID tables this function returns the names of the primary key column. For ordinary tables with a rowid column, it returns "_rowid_"
if(m_withoutRowid)
@@ -428,12 +404,12 @@ bool Table::hasAutoIncrement() const
return std::any_of(fields.begin(), fields.end(), [](const Field& f) {return f.autoIncrement(); });
}
TablePtr Table::parseSQL(const QString& sSQL)
TablePtr Table::parseSQL(const std::string& sSQL)
{
SetLocaleToC locale;
std::stringstream s;
s << sSQL.toStdString();
s << sSQL;
Sqlite3Lexer lex(s);
Sqlite3Parser parser(lex);
@@ -444,6 +420,12 @@ TablePtr Table::parseSQL(const QString& sSQL)
try
{
if(sSQL.find("[ blank]") != sSQL.npos)
{
int a = 0;
a++;
}
parser.createtable();
CreateTableWalker ctw(parser.getAST());
@@ -453,28 +435,30 @@ TablePtr Table::parseSQL(const QString& sSQL)
}
catch(antlr::ANTLRException& ex)
{
std::cerr << "Sqlite parse error: " << ex.toString() << "(" << sSQL.toStdString() << ")" << std::endl;
std::cerr << "Sqlite parse error: " << ex.toString() << "(" << sSQL << ")" << std::endl;
}
catch(...)
{
std::cerr << "Sqlite parse error: " << sSQL.toStdString() << std::endl; //TODO
std::cerr << "Sqlite parse error: " << sSQL << std::endl; //TODO
}
return TablePtr(new Table(""));
}
QString Table::sql(const QString& schema, bool ifNotExists) const
std::string Table::sql(const std::string& schema, bool ifNotExists) const
{
// Special handling for virtual tables: just build an easy create statement and copy the using part in there
if(isVirtual())
return QString("CREATE VIRTUAL TABLE %1 USING %2;").arg(ObjectIdentifier(schema, m_name).toString(true)).arg(m_virtual);
return "CREATE VIRTUAL TABLE " + ObjectIdentifier(schema, m_name).toString(true) + " USING " + m_virtual + ";";
// This is a normal table, not a virtual one
QString sql = QString("CREATE TABLE%1 %2 (\n")
.arg(ifNotExists ? QString(" IF NOT EXISTS") : QString(""))
.arg(ObjectIdentifier(schema, m_name).toString(true));
std::string sql = "CREATE TABLE ";
if(ifNotExists)
sql += "IF NOT EXISTS ";
sql += ObjectIdentifier(schema, m_name).toString(true);
sql += " (\n";
sql += fieldList().join(",\n");
sql += joinStringVector(fieldList(), ",\n");
// Constraints
ConstraintMap::const_iterator it = m_constraints.cbegin();
@@ -487,7 +471,7 @@ QString Table::sql(const QString& schema, bool ifNotExists) const
// Ignore all constraints without any fields, except for check constraints which don't rely on a field vector
if(!(it->first.empty() && it->second->type() != Constraint::CheckConstraintType))
{
sql += QString(",\n\t");
sql += ",\n\t";
sql += it->second->toSql(it->first);
}
}
@@ -503,12 +487,12 @@ QString Table::sql(const QString& schema, bool ifNotExists) const
return sql + ";";
}
void Table::addConstraint(const QStringList& fields, ConstraintPtr constraint)
void Table::addConstraint(const StringVector& fields, ConstraintPtr constraint)
{
m_constraints.insert({fields, constraint});
}
void Table::setConstraint(const QStringList& fields, ConstraintPtr constraint)
void Table::setConstraint(const StringVector& fields, ConstraintPtr constraint)
{
// Delete any old constraints of this type for these fields
removeConstraints(fields, constraint->type());
@@ -517,7 +501,7 @@ void Table::setConstraint(const QStringList& fields, ConstraintPtr constraint)
addConstraint(fields, constraint);
}
void Table::removeConstraints(const QStringList& fields, Constraint::ConstraintTypes type)
void Table::removeConstraints(const StringVector& fields, Constraint::ConstraintTypes type)
{
for(auto it = m_constraints.begin();it!=m_constraints.end();)
{
@@ -528,7 +512,7 @@ void Table::removeConstraints(const QStringList& fields, Constraint::ConstraintT
}
}
ConstraintPtr Table::constraint(const QStringList& fields, Constraint::ConstraintTypes type) const
ConstraintPtr Table::constraint(const StringVector& fields, Constraint::ConstraintTypes type) const
{
auto list = constraints(fields, type);
if(list.size())
@@ -537,7 +521,7 @@ ConstraintPtr Table::constraint(const QStringList& fields, Constraint::Constrain
return ConstraintPtr(nullptr);
}
std::vector<ConstraintPtr> Table::constraints(const QStringList& fields, Constraint::ConstraintTypes type) const
std::vector<ConstraintPtr> Table::constraints(const StringVector& fields, Constraint::ConstraintTypes type) const
{
ConstraintMap::const_iterator begin, end;
if(fields.empty())
@@ -549,7 +533,7 @@ std::vector<ConstraintPtr> Table::constraints(const QStringList& fields, Constra
}
std::vector<ConstraintPtr> clist;
std::transform(begin, end, std::back_inserter(clist), [](std::pair<QStringList, ConstraintPtr> elem){return elem.second;});
std::transform(begin, end, std::back_inserter(clist), [](std::pair<StringVector, ConstraintPtr> elem){return elem.second;});
if(type == Constraint::NoType)
{
@@ -570,12 +554,12 @@ void Table::setConstraints(const ConstraintMap& constraints)
m_constraints = constraints;
}
QStringList& Table::primaryKeyRef()
StringVector& Table::primaryKeyRef()
{
return const_cast<QStringList&>(static_cast<const Table*>(this)->primaryKey());
return const_cast<StringVector&>(static_cast<const Table*>(this)->primaryKey());
}
const QStringList& Table::primaryKey() const
const StringVector& Table::primaryKey() const
{
auto it = m_constraints.cbegin();
while(it != m_constraints.cend())
@@ -585,11 +569,11 @@ const QStringList& Table::primaryKey() const
++it;
}
static QStringList emptyFieldVector;
static StringVector emptyFieldVector;
return emptyFieldVector;
}
void Table::removeKeyFromAllConstraints(const QString& key)
void Table::removeKeyFromAllConstraints(const std::string& key)
{
// First remove all constraints with exactly that one key
m_constraints.erase({key});
@@ -597,10 +581,10 @@ void Table::removeKeyFromAllConstraints(const QString& key)
// Then delete all occurrences of the key in compound columns
for(auto it=m_constraints.begin();it!=m_constraints.end();)
{
if(it->first.contains(key))
if(contains(it->first, key))
{
QStringList k = it->first;
k.removeAll(key);
StringVector k = it->first;
k.erase(std::remove(k.begin(), k.end(), key), k.end());
m_constraints.insert({k, it->second});
it = m_constraints.erase(it);
} else {
@@ -609,7 +593,7 @@ void Table::removeKeyFromAllConstraints(const QString& key)
}
}
void Table::renameKeyInAllConstraints(const QString& key, const QString& to)
void Table::renameKeyInAllConstraints(const std::string& key, const std::string& to)
{
// Do nothing if the key hasn't really changed
if(key == to)
@@ -618,10 +602,10 @@ void Table::renameKeyInAllConstraints(const QString& key, const QString& to)
// Find all occurrences of the key and change it to the new one
for(auto it=m_constraints.begin();it!=m_constraints.end();)
{
if(it->first.contains(key))
if(contains(it->first, key))
{
QStringList k = it->first;
k.replaceInStrings(QRegExp("^" + key + "$"), to);
StringVector k = it->first;
std::replace(k.begin(), k.end(), key, to);
m_constraints.insert({k, it->second});
it = m_constraints.erase(it);
} else {
@@ -632,54 +616,53 @@ void Table::renameKeyInAllConstraints(const QString& key, const QString& to)
namespace
{
QString identifier(antlr::RefAST ident)
std::string identifier(antlr::RefAST ident)
{
QString sident = ident->getText().c_str();
std::string sident = ident->getText();
if(ident->getType() == sqlite3TokenTypes::QUOTEDID ||
ident->getType() == Sqlite3Lexer::QUOTEDLITERAL ||
ident->getType() == sqlite3TokenTypes::STRINGLITERAL)
{
// Remember the way the identifier is quoted
QChar quoteChar = sident.at(0);
std::string quoteChar(1, sident.at(0));
// Remove first and final character, i.e. the quotes
sident.remove(0, 1);
sident.chop(1);
sident = sident.substr(1, sident.size() - 2);
// Replace all remaining occurences of two succeeding quote characters and replace them
// by a single instance. This is done because two quotes can be used as a means of escaping
// the quote character, thus only the visual representation has its two quotes, the actual
// name contains only one.
sident.replace(QString(quoteChar) + quoteChar, quoteChar);
sident = std::regex_replace(sident, std::regex("\\" + quoteChar + "\\" + quoteChar), quoteChar);
}
return sident;
}
QString textAST(antlr::RefAST t)
std::string textAST(antlr::RefAST t)
{
// When this is called for a KEYWORDASTABLENAME token, we must take the child's content to get the actual value
// instead of 'KEYWORDASTABLENAME' as a string. The same applies for KEYWORDASCOLUMNNAME tokens.
if(t != antlr::nullAST && (t->getType() == sqlite3TokenTypes::KEYWORDASTABLENAME || t->getType() == sqlite3TokenTypes::KEYWORDASCOLUMNNAME))
return t->getFirstChild()->getText().c_str();
return t->getFirstChild()->getText();
else
return t->getText().c_str();
return t->getText();
}
QString concatTextAST(antlr::RefAST t, bool withspace = false)
std::string concatTextAST(antlr::RefAST t, bool withspace = false)
{
QStringList stext;
StringVector stext;
while(t != antlr::nullAST)
{
stext.append(textAST(t));
stext.push_back(textAST(t));
t = t->getNextSibling();
}
return stext.join(withspace ? " " : "");
return joinStringVector(stext, withspace ? " " : "");
}
QString concatExprAST(antlr::RefAST t)
std::string concatExprAST(antlr::RefAST t)
{
QString expr;
std::string expr;
int num_paren = 1;
while(t)
@@ -703,31 +686,31 @@ QString concatExprAST(antlr::RefAST t)
case sqlite3TokenTypes::EXISTS:
case sqlite3TokenTypes::GLOB:
case sqlite3TokenTypes::BETWEEN:
expr.append(" " + textAST(t) + " ");
expr += " " + textAST(t) + " ";
break;
case sqlite3TokenTypes::NOT:
expr.append(" " + textAST(t));
expr += " " + textAST(t);
break;
default:
expr.append(textAST(t));
expr += textAST(t);
}
t = t->getNextSibling();
}
return expr.trimmed();
return expr;
}
}
namespace {
QString tablename(const antlr::RefAST& n)
std::string tablename(const antlr::RefAST& n)
{
if(n->getType() == sqlite3TokenTypes::KEYWORDASTABLENAME)
return concatTextAST(n->getFirstChild());
else
return identifier(n);
}
QString columnname(const antlr::RefAST& n)
std::string columnname(const antlr::RefAST& n)
{
if(n->getType() == sqlite3TokenTypes::KEYWORDASCOLUMNNAME)
return concatTextAST(n->getFirstChild());
@@ -807,7 +790,7 @@ TablePtr CreateTableWalker::table()
antlr::RefAST tc = s->getFirstChild();
// Extract constraint name, if there is any
QString constraint_name;
std::string constraint_name;
if(tc->getType() == sqlite3TokenTypes::CONSTRAINT)
{
tc = tc->getNextSibling(); // CONSTRAINT
@@ -825,12 +808,12 @@ TablePtr CreateTableWalker::table()
tc = tc->getNextSibling()->getNextSibling(); // skip primary and key
tc = tc->getNextSibling(); // skip LPAREN
QStringList fields;
StringVector fields;
do
{
antlr::RefAST indexed_column = tc->getFirstChild();
QString col = columnname(indexed_column);
std::string col = columnname(indexed_column);
fields.push_back(col);
indexed_column = indexed_column->getNextSibling();
@@ -880,12 +863,12 @@ TablePtr CreateTableWalker::table()
tc = tc->getNextSibling(); // skip UNIQUE
tc = tc->getNextSibling(); // skip LPAREN
QStringList fields;
StringVector fields;
do
{
antlr::RefAST indexed_column = tc->getFirstChild();
QString col = columnname(indexed_column);
std::string col = columnname(indexed_column);
auto field = findField(tab, col);
fields.push_back(field->name());
@@ -915,7 +898,7 @@ TablePtr CreateTableWalker::table()
}
} while(tc != antlr::nullAST && tc->getType() != sqlite3TokenTypes::RPAREN);
if(fields.size() == 1 && constraint_name.isEmpty())
if(fields.size() == 1 && constraint_name.empty())
{
findField(tab, fields[0])->setUnique(true);
delete unique;
@@ -933,10 +916,10 @@ TablePtr CreateTableWalker::table()
tc = tc->getNextSibling(); // KEY
tc = tc->getNextSibling(); // LPAREN
QStringList fields;
StringVector fields;
do
{
QString col = columnname(tc);
std::string col = columnname(tc);
fields.push_back(findField(tab, col)->name());
tc = tc->getNextSibling();
@@ -955,7 +938,7 @@ TablePtr CreateTableWalker::table()
{
tc = tc->getNextSibling(); // LPAREN
QStringList fk_cols;
StringVector fk_cols;
while(tc != antlr::nullAST && tc->getType() != sqlite3TokenTypes::RPAREN)
{
if(tc->getType() != sqlite3TokenTypes::COMMA)
@@ -980,12 +963,12 @@ TablePtr CreateTableWalker::table()
tc = tc->getNextSibling(); // skip LPAREN
check->setExpression(concatExprAST(tc));
tab->addConstraint(QStringList(), ConstraintPtr(check));
tab->addConstraint(StringVector(), ConstraintPtr(check));
}
break;
default:
{
std::cout << "unknown table constraint in " << tab->name().toStdString() << std::endl;
std::cout << "unknown table constraint in " << tab->name() << std::endl;
tab->setFullyParsed(false);
}
break;
@@ -1010,14 +993,14 @@ TablePtr CreateTableWalker::table()
void CreateTableWalker::parsecolumn(Table* table, antlr::RefAST c)
{
QString colname;
QString type = "TEXT";
std::string colname;
std::string type = "TEXT";
bool autoincrement = false;
bool notnull = false;
bool unique = false;
QString defaultvalue;
QString check;
QString collation;
std::string defaultvalue;
std::string check;
std::string collation;
sqlb::PrimaryKeyConstraint* primaryKey = nullptr;
std::vector<sqlb::ForeignKeyClause*> foreignKeys;
@@ -1035,7 +1018,7 @@ void CreateTableWalker::parsecolumn(Table* table, antlr::RefAST c)
while(t != antlr::nullAST)
{
int thisType = t->getType();
type.append(textAST(t));
type += textAST(t);
t = t->getNextSibling();
if(t != antlr::nullAST)
{
@@ -1057,7 +1040,7 @@ void CreateTableWalker::parsecolumn(Table* table, antlr::RefAST c)
antlr::RefAST con = c->getFirstChild();
// Extract constraint name, if there is any
QString constraint_name;
std::string constraint_name;
if(con->getType() == sqlite3TokenTypes::CONSTRAINT)
{
con = con->getNextSibling(); // CONSTRAINT
@@ -1094,7 +1077,7 @@ void CreateTableWalker::parsecolumn(Table* table, antlr::RefAST c)
case sqlite3TokenTypes::NOT:
{
// TODO Support constraint names here
if(!constraint_name.isEmpty())
if(!constraint_name.empty())
table->setFullyParsed(false);
notnull = true;
@@ -1113,7 +1096,7 @@ void CreateTableWalker::parsecolumn(Table* table, antlr::RefAST c)
check = concatExprAST(con);
// If we have a constraint name, convert this constraint from a column into a table constaint in order to save it with our data model
if(!constraint_name.isEmpty())
if(!constraint_name.empty())
{
CheckConstraint* check_constraint = new CheckConstraint(check);
check_constraint->setName(constraint_name);
@@ -1125,7 +1108,7 @@ void CreateTableWalker::parsecolumn(Table* table, antlr::RefAST c)
case sqlite3TokenTypes::DEFAULT:
{
// TODO Support constraint names here
if(!constraint_name.isEmpty())
if(!constraint_name.empty())
table->setFullyParsed(false);
con = con->getNextSibling(); //SIGNEDNUMBER,STRING,LPAREN
@@ -1135,7 +1118,7 @@ void CreateTableWalker::parsecolumn(Table* table, antlr::RefAST c)
case sqlite3TokenTypes::UNIQUE:
{
// TODO Support constraint names here
if(!constraint_name.isEmpty())
if(!constraint_name.empty())
table->setFullyParsed(false);
unique = true;
@@ -1154,7 +1137,7 @@ void CreateTableWalker::parsecolumn(Table* table, antlr::RefAST c)
{
con = con->getNextSibling(); // LPAREN
QStringList fk_cols;
StringVector fk_cols;
while(con != antlr::nullAST && con->getType() != sqlite3TokenTypes::RPAREN)
{
if(con->getType() != sqlite3TokenTypes::COMMA)
@@ -1179,7 +1162,7 @@ void CreateTableWalker::parsecolumn(Table* table, antlr::RefAST c)
break;
default:
{
std::cout << "unknown column constraint in " << table->name().toStdString() << "." << colname.toStdString() << std::endl;
std::cout << "unknown column constraint in " << table->name() << "." << colname << std::endl;
table->setFullyParsed(false);
}
break;
@@ -1195,7 +1178,7 @@ void CreateTableWalker::parsecolumn(Table* table, antlr::RefAST c)
table->addConstraint({f.name()}, ConstraintPtr(fk));
if(primaryKey)
{
QStringList v;
StringVector v;
if(table->constraint(v, Constraint::PrimaryKeyConstraintType))
{
table->primaryKeyRef().push_back(f.name());
@@ -1209,9 +1192,9 @@ void CreateTableWalker::parsecolumn(Table* table, antlr::RefAST c)
}
}
QString CreateTableWalker::parseConflictClause(antlr::RefAST c)
std::string CreateTableWalker::parseConflictClause(antlr::RefAST c)
{
QString conflictAction;
std::string conflictAction;
if(c != antlr::nullAST && c->getType() == sqlite3TokenTypes::ON && c->getNextSibling()->getType() == sqlite3TokenTypes::CONFLICT)
{
@@ -1226,10 +1209,10 @@ QString CreateTableWalker::parseConflictClause(antlr::RefAST c)
QString IndexedColumn::toString(const QString& indent, const QString& sep) const
std::string IndexedColumn::toString(const std::string& indent, const std::string& sep) const
{
QString name = m_isExpression ? m_name : escapeIdentifier(m_name);
QString order = (m_order.isEmpty() ? QString("") : (sep + m_order));
std::string name = m_isExpression ? m_name : escapeIdentifier(m_name);
std::string order = (m_order.empty() ? "" : (sep + m_order));
return indent + name + order;
}
@@ -1249,32 +1232,38 @@ Index& Index::operator=(const Index& rhs)
return *this;
}
QStringList Index::columnSqlList() const
StringVector Index::columnSqlList() const
{
QStringList sl;
StringVector sl;
for(const IndexedColumn& c : fields)
sl << c.toString();
sl.push_back(c.toString());
return sl;
}
QString Index::sql(const QString& schema, bool ifNotExists) const
std::string Index::sql(const std::string& schema, bool ifNotExists) const
{
// Start CREATE (UNIQUE) INDEX statement
QString sql = QString("CREATE %1INDEX%2 %3 ON %4 (\n")
.arg(m_unique ? QString("UNIQUE ") : QString(""))
.arg(ifNotExists ? QString(" IF NOT EXISTS") : QString(""))
.arg(ObjectIdentifier(schema, m_name).toString(true))
.arg(sqlb::escapeIdentifier(m_table));
std::string sql;
if(m_unique)
sql = "CREATE UNIQUE INDEX ";
else
sql = "CREATE INDEX ";
if(ifNotExists)
sql += "IF NOT EXISTS ";
sql += ObjectIdentifier(schema, m_name).toString(true);
sql += " ON ";
sql += sqlb::escapeIdentifier(m_table);
sql += " (\n";
// Add column list
sql += columnSqlList().join(",\n");
sql += joinStringVector(columnSqlList(), ",\n");
// Add partial index bit
sql += QString("\n)");
if(!m_whereExpr.isEmpty())
sql += QString(" WHERE ") + m_whereExpr;
sql += "\n)";
if(!m_whereExpr.empty())
sql += " WHERE " + m_whereExpr;
return sql + ";";
}
@@ -1287,12 +1276,12 @@ FieldInfoList Index::fieldInformation() const
return result;
}
IndexPtr Index::parseSQL(const QString& sSQL)
IndexPtr Index::parseSQL(const std::string& sSQL)
{
SetLocaleToC locale;
std::stringstream s;
s << sSQL.toStdString();
s << sSQL;
Sqlite3Lexer lex(s);
Sqlite3Parser parser(lex);
@@ -1312,11 +1301,11 @@ IndexPtr Index::parseSQL(const QString& sSQL)
}
catch(antlr::ANTLRException& ex)
{
std::cerr << "Sqlite parse error: " << ex.toString() << "(" << sSQL.toStdString() << ")" << std::endl;
std::cerr << "Sqlite parse error: " << ex.toString() << "(" << sSQL << ")" << std::endl;
}
catch(...)
{
std::cerr << "Sqlite parse error: " << sSQL.toStdString() << std::endl; //TODO
std::cerr << "Sqlite parse error: " << sSQL << std::endl; //TODO
}
return IndexPtr(new Index(""));
@@ -1387,9 +1376,9 @@ IndexPtr CreateIndexWalker::index()
void CreateIndexWalker::parsecolumn(Index* index, antlr::RefAST c)
{
QString name;
std::string name;
bool isExpression;
QString order;
std::string order;
// First count the number of nodes used for the name or the expression. We reach the end of the name nodes list when we either
// get to the end of the list, get to a COMMA or a RPAREN, or get to the COLLATE keyword or get to the ASC/DESC keywords.
@@ -1415,10 +1404,10 @@ void CreateIndexWalker::parsecolumn(Index* index, antlr::RefAST c)
} else {
for(int i=0;i<number_of_name_items;i++)
{
name += c->getText().c_str() + QString(" ");
name += c->getText() + " ";
c = c->getNextSibling();
}
name.chop(1);
name = name.substr(0, name.size()-1);
isExpression = true;
}
@@ -1444,7 +1433,7 @@ void CreateIndexWalker::parsecolumn(Index* index, antlr::RefAST c)
ViewPtr View::parseSQL(const QString& sSQL)
ViewPtr View::parseSQL(const std::string& sSQL)
{
// TODO
@@ -1453,12 +1442,12 @@ ViewPtr View::parseSQL(const QString& sSQL)
return v;
}
QStringList View::fieldNames() const
StringVector View::fieldNames() const
{
QStringList sl;
StringVector sl;
for(const Field& f : fields)
sl << f.name();
sl.push_back(f.name());
return sl;
}
@@ -1472,7 +1461,7 @@ FieldInfoList View::fieldInformation() const
}
TriggerPtr Trigger::parseSQL(const QString& sSQL)
TriggerPtr Trigger::parseSQL(const std::string& sSQL)
{
// TODO
+188 -188
View File
@@ -5,8 +5,7 @@
#include <vector>
#include <unordered_map>
#include <memory>
#include <QString>
#include <QVariant>
#include <algorithm>
template<typename C, typename E>
bool contains(const C& container, E element)
@@ -14,34 +13,16 @@ bool contains(const C& container, E element)
return std::find(container.begin(), container.end(), element) != container.end();
}
namespace sqlb {
#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
struct QHashCombine {
typedef uint result_type;
template <typename T>
Q_DECL_CONSTEXPR result_type operator()(uint seed, const T &t) const Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(t)))
// combiner taken from N3876 / boost::hash_combine
{ return seed ^ (qHash(t) + 0x9e3779b9 + (seed << 6) + (seed >> 2)) ; }
};
template <typename InputIterator>
inline uint qHashRange(InputIterator first, InputIterator last, uint seed = 0)
Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(*first))) // assume iterator operations don't throw
{
return std::accumulate(first, last, seed, QHashCombine());
}
#endif
template<typename T>
uint qHash(const QList<T>& key, uint seed = 0)
Q_DECL_NOEXCEPT_EXPR(noexcept(qHashRange(key.cbegin(), key.cend(), seed)))
bool compare_ci(const T& a, const T& b)
{
return qHashRange(key.cbegin(), key.cend(), seed);
return std::equal(a.begin(), a.end(), b.begin(), [](char c1, char c2) {
// TODO: Do we need to make this UTF-8-aware?
return std::tolower(c1) == std::tolower(c2);
});
}
#endif
namespace sqlb {
enum escapeQuoting {
DoubleQuotes,
@@ -49,37 +30,36 @@ enum escapeQuoting {
SquareBrackets
};
using StringVector = std::vector<std::string>;
// Set quoting style for escapeIdentifier
void setIdentifierQuoting(escapeQuoting toQuoting);
QString escapeIdentifier(QString id);
std::string escapeIdentifier(std::string id);
QStringList escapeIdentifier(QStringList ids);
StringVector escapeIdentifier(StringVector ids);
std::string joinStringVector(const StringVector& vec, const std::string& delim);
class ObjectIdentifier
{
public:
ObjectIdentifier(const QString& schema, const QString& name)
ObjectIdentifier(const std::string& schema, const std::string& name)
: m_schema(schema),
m_name(name)
{
}
ObjectIdentifier()
: m_schema("main"),
m_name(QString())
: m_schema("main")
{
}
explicit ObjectIdentifier(QVariant variant)
explicit ObjectIdentifier(const std::string& variant)
{
QStringList str = variant.toStringList();
if(str.size())
{
m_schema = str.first();
if(str.size() >= 2)
m_name = str.last();
}
// Try to unserialise the parameter first. If that does not work, just assume it's an object name for the main schema
clear();
if(!fromSerialised(variant))
m_name = variant;
}
bool operator==(const ObjectIdentifier& rhs) const
@@ -92,10 +72,10 @@ public:
return toDisplayString() < rhs.toDisplayString();
}
const QString& schema() const { return m_schema; }
const QString& name() const { return m_name; }
void setSchema(const QString& schema) { m_schema = schema; }
void setName(const QString& name) { m_name = name; }
const std::string& schema() const { return m_schema; }
const std::string& name() const { return m_name; }
void setSchema(const std::string& schema) { m_schema = schema; }
void setName(const std::string& name) { m_name = name; }
void clear()
{
@@ -103,43 +83,64 @@ public:
m_name.clear();
}
bool isEmpty() const { return m_name.isEmpty(); }
bool isEmpty() const { return m_name.empty(); }
// This returns a string which can be used in SQL statements
QString toString(bool shortName = false) const
std::string toString(bool shortName = false) const
{
if(shortName && m_schema == "main")
return sqlb::escapeIdentifier(m_name);
else
return QString("%1.%2").arg(sqlb::escapeIdentifier(m_schema)).arg(sqlb::escapeIdentifier(m_name));
return sqlb::escapeIdentifier(m_schema) + "." + sqlb::escapeIdentifier(m_name);
}
// This returns a string which can be used in the user interface
QString toDisplayString() const
std::string toDisplayString() const
{
if(m_schema == "main")
return m_name;
else
return QString("%1.%2").arg(m_schema).arg(m_name);
return m_schema + "." + m_name;
}
QVariant toVariant() const
std::string toSerialised() const
{
QStringList result;
result << m_schema << m_name;
return QVariant(result);
return std::to_string(m_schema.size()) + "," + std::to_string(m_name.size()) + ":" + m_schema + m_name;
}
bool fromSerialised(const std::string& serialised)
{
auto pos_comma = serialised.find(",");
auto pos_colon = serialised.find(":");
if(pos_comma == serialised.npos || pos_colon == serialised.npos)
return false;
size_t size_schema, size_name;
size_schema = std::stoul(serialised.substr(0, pos_comma));
size_name = std::stoul(serialised.substr(pos_comma+1, pos_colon-pos_comma));
if(pos_colon + size_schema + size_name + 1 != serialised.size())
return false;
m_schema = serialised.substr(pos_colon + 1, size_schema);
m_name = serialised.substr(pos_colon + size_schema + 1, size_name);
return true;
}
private:
QString m_schema;
QString m_name;
std::string m_schema;
std::string m_name;
};
struct StringListHash
struct StringVectorHash
{
size_t operator()(const QStringList& key) const
size_t operator()(const StringVector& key) const
{
return qHash(key);
// This is taken from Boost
size_t seed = 0;
for(const std::string& s : key)
seed ^= std::hash<std::string>{}(s) + 0x9e3779b9 + (seed << 6) + ( seed >> 2);
return seed;
}
};
@@ -160,18 +161,18 @@ using TriggerPtr = std::shared_ptr<Trigger>;
using ConstraintPtr = std::shared_ptr<Constraint>;
using FieldVector = std::vector<Field>;
using IndexedColumnVector = std::vector<IndexedColumn>;
using ConstraintMap = std::unordered_multimap<QStringList, ConstraintPtr, StringListHash>;
using ConstraintMap = std::unordered_multimap<StringVector, ConstraintPtr, StringVectorHash>;
using FieldInfoList = std::vector<FieldInfo>;
struct FieldInfo
{
FieldInfo(const QString& name_, const QString& type_, const QString& sql_)
FieldInfo(const std::string& name_, const std::string& type_, const std::string& sql_)
: name(name_), type(type_), sql(sql_)
{}
QString name;
QString type;
QString sql;
std::string name;
std::string type;
std::string sql;
};
class Object
@@ -185,21 +186,21 @@ public:
Trigger
};
explicit Object(const QString& name): m_name(name), m_fullyParsed(false) {}
explicit Object(const std::string& name): m_name(name), m_fullyParsed(false) {}
virtual ~Object() {}
bool operator==(const Object& rhs) const;
virtual Types type() const = 0;
static QString typeToString(Types type);
static std::string typeToString(Types type);
void setName(const QString& name) { m_name = name; }
const QString& name() const { return m_name; }
void setName(const std::string& name) { m_name = name; }
const std::string& name() const { return m_name; }
void setOriginalSql(const QString& original_sql) { m_originalSql = original_sql; }
QString originalSql() const { return m_originalSql; }
void setOriginalSql(const std::string& original_sql) { m_originalSql = original_sql; }
std::string originalSql() const { return m_originalSql; }
virtual QString baseTable() const { return QString(); }
virtual std::string baseTable() const { return std::string(); }
void setFullyParsed(bool fully_parsed) { m_fullyParsed = fully_parsed; }
bool fullyParsed() const { return m_fullyParsed; }
@@ -210,13 +211,13 @@ public:
* @brief Returns the CREATE statement for this object
* @param schema The schema name of the object
* @param ifNotExists If set to true the "IF NOT EXISTS" qualifier will be added to the create statement
* @return A QString with the CREATE statement.
* @return A std::string with the CREATE statement.
*/
virtual QString sql(const QString& schema = QString("main"), bool ifNotExists = false) const = 0;
virtual std::string sql(const std::string& schema = std::string("main"), bool ifNotExists = false) const = 0;
protected:
QString m_name;
QString m_originalSql;
std::string m_name;
std::string m_originalSql;
bool m_fullyParsed;
};
@@ -232,7 +233,7 @@ public:
CheckConstraintType,
};
explicit Constraint(const QString& name = QString())
explicit Constraint(const std::string& name = std::string())
: m_name(name)
{
}
@@ -240,49 +241,48 @@ public:
virtual ConstraintTypes type() const = 0;
void setName(const QString& name) { m_name = name; }
const QString& name() const { return m_name; }
void setName(const std::string& name) { m_name = name; }
const std::string& name() const { return m_name; }
virtual QString toSql(const QStringList& applyOn) const = 0;
virtual std::string toSql(const StringVector& applyOn) const = 0;
protected:
QString m_name;
std::string m_name;
};
class ForeignKeyClause : public Constraint
{
public:
ForeignKeyClause(const QString& table = QString(), const QStringList& columns = QStringList(), const QString& constraint = QString())
ForeignKeyClause(const std::string& table = std::string(), const StringVector& columns = {}, const std::string& constraint = std::string())
: m_table(table),
m_columns(columns),
m_constraint(constraint),
m_override(QString())
m_constraint(constraint)
{
}
bool isSet() const;
QString toString() const;
void setFromString(const QString& fk);
std::string toString() const;
void setFromString(const std::string& fk);
void setTable(const QString& table) { m_override = QString(); m_table = table; }
const QString& table() const { return m_table; }
void setTable(const std::string& table) { m_override.clear(); m_table = table; }
const std::string& table() const { return m_table; }
void setColumns(const QStringList& columns) { m_columns = columns; }
const QStringList& columns() const { return m_columns; }
void setColumns(const StringVector& columns) { m_columns = columns; }
const StringVector& columns() const { return m_columns; }
void setConstraint(const QString& constraint) { m_constraint = constraint; }
const QString& constraint() const { return m_constraint; }
void setConstraint(const std::string& constraint) { m_constraint = constraint; }
const std::string& constraint() const { return m_constraint; }
QString toSql(const QStringList& applyOn) const override;
std::string toSql(const StringVector& applyOn) const override;
ConstraintTypes type() const override { return ForeignKeyConstraintType; }
private:
QString m_table;
QStringList m_columns;
QString m_constraint;
std::string m_table;
StringVector m_columns;
std::string m_constraint;
QString m_override;
std::string m_override;
};
class UniqueConstraint : public Constraint
@@ -290,7 +290,7 @@ class UniqueConstraint : public Constraint
public:
UniqueConstraint() {}
QString toSql(const QStringList& applyOn) const override;
std::string toSql(const StringVector& applyOn) const override;
ConstraintTypes type() const override { return UniqueConstraintType; }
};
@@ -300,34 +300,34 @@ class PrimaryKeyConstraint : public Constraint
public:
PrimaryKeyConstraint() {}
void setConflictAction(const QString& conflict) { m_conflictAction = conflict; }
const QString& conflictAction() const { return m_conflictAction; }
void setConflictAction(const std::string& conflict) { m_conflictAction = conflict; }
const std::string& conflictAction() const { return m_conflictAction; }
QString toSql(const QStringList& applyOn) const override;
std::string toSql(const StringVector& applyOn) const override;
ConstraintTypes type() const override { return PrimaryKeyConstraintType; }
private:
QString m_conflictAction;
std::string m_conflictAction;
};
class CheckConstraint : public Constraint
{
public:
explicit CheckConstraint(const QString& expr = QString())
explicit CheckConstraint(const std::string& expr = std::string())
: m_expression(expr)
{
}
void setExpression(const QString& expr) { m_expression = expr; }
QString expression() const { return m_expression; }
void setExpression(const std::string& expr) { m_expression = expr; }
const std::string& expression() const { return m_expression; }
QString toSql(const QStringList& applyOn) const override;
std::string toSql(const StringVector& applyOn) const override;
ConstraintTypes type() const override { return CheckConstraintType; }
private:
QString m_expression;
std::string m_expression;
};
class Field
@@ -339,13 +339,13 @@ public:
m_unique(false)
{}
Field(const QString& name,
const QString& type,
Field(const std::string& name,
const std::string& type,
bool notnull = false,
const QString& defaultvalue = "",
const QString& check = "",
const std::string& defaultvalue = "",
const std::string& check = "",
bool unique = false,
const QString& collation = QString())
const std::string& collation = "")
: m_name(name)
, m_type(type)
, m_notnull(notnull)
@@ -358,16 +358,16 @@ public:
bool operator==(const Field& rhs) const;
QString toString(const QString& indent = "\t", const QString& sep = "\t") const;
std::string toString(const std::string& indent = "\t", const std::string& sep = "\t") const;
void setName(const QString& name) { m_name = name; }
void setType(const QString& type) { m_type = type; }
void setName(const std::string& name) { m_name = name; }
void setType(const std::string& type) { m_type = type; }
void setNotNull(bool notnull = true) { m_notnull = notnull; }
void setCheck(const QString& check) { m_check = check; }
void setDefaultValue(const QString& defaultvalue) { m_defaultvalue = defaultvalue; }
void setCheck(const std::string& check) { m_check = check; }
void setDefaultValue(const std::string& defaultvalue) { m_defaultvalue = defaultvalue; }
void setAutoIncrement(bool autoinc) { m_autoincrement = autoinc; }
void setUnique(bool u) { m_unique = u; }
void setCollation(const QString& collation) { m_collation = collation; }
void setCollation(const std::string& collation) { m_collation = collation; }
bool isText() const;
bool isInteger() const;
@@ -376,32 +376,32 @@ public:
bool isNumeric() const;
// Type affinity of the column according to SQLite3 rules
QString affinity() const;
std::string affinity() const;
const QString& name() const { return m_name; }
const QString& type() const { return m_type; }
const std::string& name() const { return m_name; }
const std::string& type() const { return m_type; }
bool notnull() const { return m_notnull; }
const QString& check() const { return m_check; }
const QString& defaultValue() const { return m_defaultvalue; }
const std::string& check() const { return m_check; }
const std::string& defaultValue() const { return m_defaultvalue; }
bool autoIncrement() const { return m_autoincrement; }
bool unique() const { return m_unique; }
const QString& collation() const { return m_collation; }
const std::string& collation() const { return m_collation; }
private:
QString m_name;
QString m_type;
std::string m_name;
std::string m_type;
bool m_notnull;
QString m_check;
QString m_defaultvalue;
std::string m_check;
std::string m_defaultvalue;
bool m_autoincrement; //! this is stored here for simplification
bool m_unique;
QString m_collation;
std::string m_collation;
};
class Table : public Object
{
public:
explicit Table(const QString& name): Object(name), m_withoutRowid(false) {}
explicit Table(const std::string& name): Object(name), m_withoutRowid(false) {}
Table& operator=(const Table& rhs);
bool operator==(const Table& rhs) const;
@@ -414,81 +414,81 @@ public:
/**
* @brief Returns the CREATE TABLE statement for this table object
* @return A QString with the CREATE TABLE object.
* @return A std::string with the CREATE TABLE object.
*/
QString sql(const QString& schema = QString("main"), bool ifNotExists = false) const override;
std::string sql(const std::string& schema = "main", bool ifNotExists = false) const override;
QStringList fieldNames() const;
StringVector fieldNames() const;
QStringList rowidColumns() const;
StringVector rowidColumns() const;
void setWithoutRowidTable(bool without_rowid) { m_withoutRowid = without_rowid; }
bool withoutRowidTable() const { return m_withoutRowid; }
void setVirtualUsing(const QString& virt_using) { m_virtual = virt_using; }
QString virtualUsing() const { return m_virtual; }
bool isVirtual() const { return !m_virtual.isEmpty(); }
void setVirtualUsing(const std::string& virt_using) { m_virtual = virt_using; }
const std::string& virtualUsing() const { return m_virtual; }
bool isVirtual() const { return !m_virtual.empty(); }
FieldInfoList fieldInformation() const override;
void addConstraint(const QStringList& fields, ConstraintPtr constraint);
void setConstraint(const QStringList& fields, ConstraintPtr constraint);
void removeConstraints(const QStringList& fields = QStringList(), Constraint::ConstraintTypes type = Constraint::NoType); //! Only removes the first constraint, if any
ConstraintPtr constraint(const QStringList& fields = QStringList(), Constraint::ConstraintTypes type = Constraint::NoType) const; //! Only returns the first constraint, if any
std::vector<ConstraintPtr> constraints(const QStringList& fields = QStringList(), Constraint::ConstraintTypes type = Constraint::NoType) const;
void addConstraint(const StringVector& fields, ConstraintPtr constraint);
void setConstraint(const StringVector& fields, ConstraintPtr constraint);
void removeConstraints(const StringVector& fields = StringVector(), Constraint::ConstraintTypes type = Constraint::NoType); //! Only removes the first constraint, if any
ConstraintPtr constraint(const StringVector& fields = StringVector(), Constraint::ConstraintTypes type = Constraint::NoType) const; //! Only returns the first constraint, if any
std::vector<ConstraintPtr> constraints(const StringVector& fields = StringVector(), Constraint::ConstraintTypes type = Constraint::NoType) const;
ConstraintMap allConstraints() const { return m_constraints; }
void setConstraints(const ConstraintMap& constraints);
QStringList& primaryKeyRef();
const QStringList& primaryKey() const;
void removeKeyFromAllConstraints(const QString& key);
void renameKeyInAllConstraints(const QString& key, const QString& to);
StringVector& primaryKeyRef();
const StringVector& primaryKey() const;
void removeKeyFromAllConstraints(const std::string& key);
void renameKeyInAllConstraints(const std::string& key, const std::string& to);
/**
* @brief parseSQL Parses the create Table statement in sSQL.
* @param sSQL The create table statement.
* @return The table object. The table object may be empty if parsing failed.
*/
static TablePtr parseSQL(const QString& sSQL);
static TablePtr parseSQL(const std::string& sSQL);
private:
QStringList fieldList() const;
StringVector fieldList() const;
bool hasAutoIncrement() const;
private:
bool m_withoutRowid;
ConstraintMap m_constraints;
QString m_virtual;
std::string m_virtual;
};
class IndexedColumn
{
public:
IndexedColumn(const QString& name, bool expr, const QString& order = QString())
IndexedColumn(const std::string& name, bool expr, const std::string& order = std::string())
: m_name(name),
m_isExpression(expr),
m_order(order)
{
}
void setName(const QString& name) { m_name = name; }
QString name() const { return m_name; }
void setName(const std::string& name) { m_name = name; }
const std::string& name() const { return m_name; }
void setExpression(bool expr) { m_isExpression = expr; }
bool expression() const { return m_isExpression; }
void setOrder(const QString& order) { m_order = order.toUpper(); }
QString order() const { return m_order; }
void setOrder(const std::string& order) { m_order = order; }
std::string order() const { return m_order; }
QString toString(const QString& indent = "\t", const QString& sep = "\t") const;
std::string toString(const std::string& indent = "\t", const std::string& sep = "\t") const;
private:
QString m_name;
std::string m_name;
bool m_isExpression;
QString m_order;
std::string m_order;
};
class Index : public Object
{
public:
explicit Index(const QString& name): Object(name), m_unique(false) {}
explicit Index(const std::string& name): Object(name), m_unique(false) {}
Index& operator=(const Index& rhs);
Types type() const override { return Object::Index; }
@@ -497,55 +497,55 @@ public:
using field_type = IndexedColumn;
using field_iterator = IndexedColumnVector::iterator;
QString baseTable() const override { return m_table; }
std::string baseTable() const override { return m_table; }
void setUnique(bool unique) { m_unique = unique; }
bool unique() const { return m_unique; }
void setTable(const QString& table) { m_table = table; }
const QString& table() const { return m_table; }
void setTable(const std::string& table) { m_table = table; }
const std::string& table() const { return m_table; }
void setWhereExpr(const QString& expr) { m_whereExpr = expr; }
const QString& whereExpr() const { return m_whereExpr; }
void setWhereExpr(const std::string& expr) { m_whereExpr = expr; }
const std::string& whereExpr() const { return m_whereExpr; }
/**
* @brief Returns the CREATE INDEX statement for this index object
* @return A QString with the CREATE INDEX object.
* @return A std::string with the CREATE INDEX object.
*/
QString sql(const QString& schema = QString("main"), bool ifNotExists = false) const override;
std::string sql(const std::string& schema = "main", bool ifNotExists = false) const override;
/**
* @brief parseSQL Parses the CREATE INDEX statement in sSQL.
* @param sSQL The create index statement.
* @return The index object. The index object may be empty if the parsing failed.
*/
static IndexPtr parseSQL(const QString& sSQL);
static IndexPtr parseSQL(const std::string& sSQL);
FieldInfoList fieldInformation() const override;
private:
QStringList columnSqlList() const;
StringVector columnSqlList() const;
bool m_unique;
QString m_table;
QString m_whereExpr;
std::string m_table;
std::string m_whereExpr;
};
class View : public Object
{
public:
explicit View(const QString& name): Object(name) {}
explicit View(const std::string& name): Object(name) {}
Types type() const override { return Object::View; }
FieldVector fields;
QString sql(const QString& schema = QString("main"), bool ifNotExists = false) const override
{ /* TODO */ Q_UNUSED(schema); Q_UNUSED(ifNotExists); return m_originalSql; }
std::string sql(const std::string& /*schema*/ = "main", bool /*ifNotExists*/ = false) const override
{ /* TODO */ return m_originalSql; }
static ViewPtr parseSQL(const QString& sSQL);
static ViewPtr parseSQL(const std::string& sSQL);
QStringList fieldNames() const;
StringVector fieldNames() const;
FieldInfoList fieldInformation() const override;
};
@@ -553,22 +553,22 @@ public:
class Trigger : public Object
{
public:
explicit Trigger(const QString& name): Object(name) {}
explicit Trigger(const std::string& name): Object(name) {}
Types type() const override { return Object::Trigger; }
QString sql(const QString& schema = QString("main"), bool ifNotExists = false) const override
{ /* TODO */ Q_UNUSED(schema); Q_UNUSED(ifNotExists); return m_originalSql; }
std::string sql(const std::string& /*schema*/ = "main", bool /*ifNotExists*/ = false) const override
{ /* TODO */ return m_originalSql; }
static TriggerPtr parseSQL(const QString& sSQL);
static TriggerPtr parseSQL(const std::string& sSQL);
QString baseTable() const override { return m_table; }
std::string baseTable() const override { return m_table; }
void setTable(const QString& table) { m_table = table; }
QString table() const { return m_table; }
void setTable(const std::string& table) { m_table = table; }
std::string table() const { return m_table; }
private:
QString m_table;
std::string m_table;
};
/**
@@ -579,24 +579,24 @@ private:
* object.fields.end() if the field couldn't be found.
*/
template<typename T>
typename T::field_iterator findField(T* object, const QString& name)
typename T::field_iterator findField(T* object, const std::string& name)
{
return std::find_if(object->fields.begin(), object->fields.end(), [&name](const typename T::field_type& f) {
return f.name().compare(name, Qt::CaseInsensitive) == 0;
return compare_ci(name, f.name());
});
}
template<typename T>
typename T::field_iterator findField(const T* object, const QString& name)
typename T::field_iterator findField(const T* object, const std::string& name)
{
return findField(const_cast<T*>(object), name);
}
template<typename T>
typename std::remove_reference<T>::type::field_iterator findField(std::shared_ptr<T> object, const QString& name)
typename std::remove_reference<T>::type::field_iterator findField(std::shared_ptr<T> object, const std::string& name)
{
return findField(object.get(), name);
}
template<typename T>
typename std::remove_reference<T>::type::field_iterator findField(T& object, const QString& name)
typename std::remove_reference<T>::type::field_iterator findField(T& object, const std::string& name)
{
return findField(&object, name);
}
@@ -611,7 +611,7 @@ template<typename T> struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {
* @return true if sucessful, otherwise false
*/
template<typename T>
bool removeField(T* object, const QString& name)
bool removeField(T* object, const std::string& name)
{
auto index = findField(object, name);
if(index != object->fields.end())
@@ -622,12 +622,12 @@ bool removeField(T* object, const QString& name)
return false;
}
template<typename T, typename = typename std::enable_if<is_shared_ptr<T>::value>::type>
bool removeField(T object, const QString& name)
bool removeField(T object, const std::string& name)
{
return removeField(object.get(), name);
}
template<typename T, typename = typename std::enable_if<!is_shared_ptr<T>::value>::type>
bool removeField(T& object, const QString& name)
bool removeField(T& object, const std::string& name)
{
return removeField(&object, name);
}
+115 -110
View File
@@ -21,6 +21,7 @@
#include <algorithm>
#include <cctype>
#include <json.hpp>
#include <regex>
using json = nlohmann::json;
@@ -39,6 +40,13 @@ struct Callback<Ret(Params...)> {
template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::func;
namespace sqlb {
QString escapeIdentifier(const QString& id)
{
return QString::fromStdString(escapeIdentifier(id.toStdString()));
}
}
// collation callbacks
int collCompare(void* /*pArg*/, int sizeA, const void* sA, int sizeB, const void* sB)
{
@@ -761,13 +769,13 @@ bool DBBrowserDB::dump(const QString& filePath,
it.next();
// Remove the sqlite_stat1 and the sqlite_sequence tables if they exist. Also remove any tables which are not selected for export.
if(it.value()->name() == "sqlite_stat1" || it.value()->name() == "sqlite_sequence" || !tablesToDump.contains(it.value()->name()))
if(it.value()->name() == "sqlite_stat1" || it.value()->name() == "sqlite_sequence" || !tablesToDump.contains(QString::fromStdString(it.value()->name())))
{
it.remove();
} else {
// Otherwise get the number of records in this table
numRecordsTotal += querySingleValueFromDb(QString("SELECT COUNT(*) FROM %1;")
.arg(sqlb::ObjectIdentifier("main", it.value()->name()).toString())).toUInt();
.arg(QString::fromStdString(sqlb::ObjectIdentifier("main", it.value()->name()).toString()))).toUInt();
}
}
@@ -791,12 +799,12 @@ bool DBBrowserDB::dump(const QString& filePath,
{
// Write the SQL string used to create this table to the output file
if(!keepOldSchema)
stream << QString("DROP TABLE IF EXISTS %1;\n").arg(sqlb::escapeIdentifier(it->name()));
stream << QString("DROP TABLE IF EXISTS %1;\n").arg(QString::fromStdString(sqlb::escapeIdentifier(it->name())));
if(it->fullyParsed())
stream << it->sql("main", true) << "\n";
stream << QString::fromStdString(it->sql("main", true)) << "\n";
else
stream << it->originalSql() << ";\n";
stream << QString::fromStdString(it->originalSql()) << ";\n";
}
}
@@ -806,9 +814,9 @@ bool DBBrowserDB::dump(const QString& filePath,
for(auto it : tables)
{
// get columns
QStringList cols(std::dynamic_pointer_cast<sqlb::Table>(it)->fieldNames());
sqlb::StringVector cols = std::dynamic_pointer_cast<sqlb::Table>(it)->fieldNames();
QString sQuery = QString("SELECT * FROM %1;").arg(sqlb::escapeIdentifier(it->name()));
QString sQuery = QString("SELECT * FROM %1;").arg(QString::fromStdString(sqlb::escapeIdentifier(it->name())));
QByteArray utf8Query = sQuery.toUtf8();
sqlite3_stmt *stmt;
QString lineSep(QString(")%1\n").arg(insertNewSyntx?',':';'));
@@ -826,9 +834,9 @@ bool DBBrowserDB::dump(const QString& filePath,
if (!insertNewSyntx || !counter)
{
stream << "INSERT INTO " << sqlb::escapeIdentifier(it->name());
stream << "INSERT INTO " << QString::fromStdString(sqlb::escapeIdentifier(it->name()));
if (insertColNames)
stream << " (" << sqlb::escapeIdentifier(cols).join(",") << ")";
stream << " (" << QString::fromStdString(sqlb::joinStringVector(sqlb::escapeIdentifier(cols), ",")) << ")";
stream << " VALUES (";
}
else
@@ -904,21 +912,21 @@ bool DBBrowserDB::dump(const QString& filePath,
// If this object is based on a table (e.g. is an index for that table) it depends on the existence of this table.
// So if we didn't export the base table this depends on, don't export this object either.
if(!it->baseTable().isEmpty() && !tablesToDump.contains(it->baseTable()))
if(!it->baseTable().empty() && !tablesToDump.contains(QString::fromStdString(it->baseTable())))
continue;
// Write the SQL string used to create this object to the output file
if(!it->originalSql().isEmpty())
if(!it->originalSql().empty())
{
if(!keepOldSchema)
stream << QString("DROP %1 IF EXISTS %2;\n")
.arg(sqlb::Object::typeToString(it->type()).toUpper())
.arg(sqlb::escapeIdentifier(it->name()));
.arg(QString::fromStdString(sqlb::Object::typeToString(it->type())).toUpper())
.arg(QString::fromStdString(sqlb::escapeIdentifier(it->name())));
if(it->fullyParsed())
stream << it->sql("main", true) << "\n";
stream << QString::fromStdString(it->sql("main", true)) << "\n";
else
stream << it->originalSql() << ";\n";
stream << QString::fromStdString(it->originalSql()) << ";\n";
}
}
}
@@ -1168,23 +1176,23 @@ QByteArray DBBrowserDB::querySingleValueFromDb(const QString& sql, bool log, Cho
return retval;
}
bool DBBrowserDB::getRow(const sqlb::ObjectIdentifier& table, const QString& rowid, QVector<QByteArray>& rowdata)
bool DBBrowserDB::getRow(const sqlb::ObjectIdentifier& table, const QString& rowid, std::vector<QByteArray>& rowdata)
{
waitForDbRelease();
if(!_db)
return false;
QString sQuery = QString("SELECT * FROM %1 WHERE ")
.arg(table.toString());
.arg(QString::fromStdString(table.toString()));
// For a single rowid column we can use a simple WHERE condition, for multiple rowid columns we have to use sqlb_make_single_value to decode the composed rowid values.
QStringList pks = getObjectByName<sqlb::Table>(table)->rowidColumns();
sqlb::StringVector pks = getObjectByName<sqlb::Table>(table)->rowidColumns();
if(pks.size() == 1)
{
sQuery += QString("%1='%2;").arg(sqlb::escapeIdentifier(pks.front())).arg(rowid);
sQuery += QString("%1='%2;").arg(QString::fromStdString(sqlb::escapeIdentifier(pks.front()))).arg(rowid);
} else {
sQuery += QString("sqlb_make_single_value(%1)='%2';")
.arg(sqlb::escapeIdentifier(pks).join(","))
.arg(QString::fromStdString(sqlb::joinStringVector(sqlb::escapeIdentifier(pks), ",")))
.arg(QString(rowid).replace("'", "''"));
}
@@ -1200,13 +1208,13 @@ bool DBBrowserDB::getRow(const sqlb::ObjectIdentifier& table, const QString& row
{
if(sqlite3_column_type(stmt, i) == SQLITE_NULL)
{
rowdata.append(QByteArray());
rowdata.push_back(QByteArray());
} else {
int bytes = sqlite3_column_bytes(stmt, i);
if(bytes)
rowdata.append(QByteArray(static_cast<const char*>(sqlite3_column_blob(stmt, i)), bytes));
rowdata.push_back(QByteArray(static_cast<const char*>(sqlite3_column_blob(stmt, i)), bytes));
else
rowdata.append(QByteArray(""));
rowdata.push_back(QByteArray(""));
}
}
ret = true;
@@ -1219,7 +1227,7 @@ bool DBBrowserDB::getRow(const sqlb::ObjectIdentifier& table, const QString& row
QString DBBrowserDB::max(const sqlb::ObjectIdentifier& tableName, const sqlb::Field& field) const
{
QString sQuery = QString("SELECT MAX(CAST(%2 AS INTEGER)) FROM %1;").arg(tableName.toString()).arg(sqlb::escapeIdentifier(field.name()));
QString sQuery = QString("SELECT MAX(CAST(%2 AS INTEGER)) FROM %1;").arg(QString::fromStdString(tableName.toString())).arg(QString::fromStdString(sqlb::escapeIdentifier(field.name())));
QByteArray utf8Query = sQuery.toUtf8();
sqlite3_stmt *stmt;
QString ret = "0";
@@ -1238,18 +1246,18 @@ QString DBBrowserDB::max(const sqlb::ObjectIdentifier& tableName, const sqlb::Fi
return ret;
}
QString DBBrowserDB::emptyInsertStmt(const QString& schemaName, const sqlb::Table& t, const QString& pk_value) const
QString DBBrowserDB::emptyInsertStmt(const std::string& schemaName, const sqlb::Table& t, const QString& pk_value) const
{
QString stmt = QString("INSERT INTO %1.%2").arg(sqlb::escapeIdentifier(schemaName)).arg(sqlb::escapeIdentifier(t.name()));
QString stmt = QString("INSERT INTO %1.%2").arg(QString::fromStdString(sqlb::escapeIdentifier(schemaName))).arg(QString::fromStdString(sqlb::escapeIdentifier(t.name())));
QStringList vals;
QStringList fields;
sqlb::StringVector fields;
for(const sqlb::Field& f : t.fields)
{
sqlb::ConstraintPtr pk = t.constraint({f.name()}, sqlb::Constraint::PrimaryKeyConstraintType);
if(pk)
{
fields << f.name();
fields.push_back(f.name());
if(!pk_value.isNull())
{
@@ -1265,7 +1273,7 @@ QString DBBrowserDB::emptyInsertStmt(const QString& schemaName, const sqlb::Tabl
}
}
} else if(f.notnull() && f.defaultValue().length() == 0) {
fields << f.name();
fields.push_back(f.name());
if(f.isInteger())
vals << "0";
@@ -1276,7 +1284,7 @@ QString DBBrowserDB::emptyInsertStmt(const QString& schemaName, const sqlb::Tabl
// or we will never see it.
if(f.defaultValue().length() == 0)
{
fields << f.name();
fields.push_back(f.name());
vals << "NULL";
}
}
@@ -1287,7 +1295,7 @@ QString DBBrowserDB::emptyInsertStmt(const QString& schemaName, const sqlb::Tabl
stmt.append(" DEFAULT VALUES;");
} else {
stmt.append("(");
stmt.append(sqlb::escapeIdentifier(fields).join(","));
stmt.append(QString::fromStdString(sqlb::joinStringVector(sqlb::escapeIdentifier(fields), ",")));
stmt.append(") VALUES (");
stmt.append(vals.join(","));
stmt.append(");");
@@ -1314,7 +1322,7 @@ QString DBBrowserDB::addRecord(const sqlb::ObjectIdentifier& tablename)
{
// For multiple rowid columns we just use the value of the last one and increase that one by one. If this doesn't yield a valid combination
// the insert record dialog should pop up automatically.
pk_value = QString::number(max(tablename, *sqlb::findField(table, table->rowidColumns().last())).toLongLong() + 1);
pk_value = QString::number(max(tablename, *sqlb::findField(table, table->rowidColumns().back())).toLongLong() + 1);
sInsertstmt = emptyInsertStmt(tablename.schema(), *table, pk_value);
} else {
sInsertstmt = emptyInsertStmt(tablename.schema(), *table);
@@ -1332,13 +1340,13 @@ QString DBBrowserDB::addRecord(const sqlb::ObjectIdentifier& tablename)
}
}
bool DBBrowserDB::deleteRecords(const sqlb::ObjectIdentifier& table, const QStringList& rowids, const std::vector<std::string>& pseudo_pk)
bool DBBrowserDB::deleteRecords(const sqlb::ObjectIdentifier& table, const QStringList& rowids, const sqlb::StringVector& pseudo_pk)
{
if (!isOpen()) return false;
// Get primary key of the object to edit.
QStringList pks = primaryKeyForEditing(table, pseudo_pk);
if(pks.isEmpty())
sqlb::StringVector pks = primaryKeyForEditing(table, pseudo_pk);
if(pks.empty())
{
lastErrorMessage = tr("Cannot delete this object");
return false;
@@ -1355,15 +1363,15 @@ bool DBBrowserDB::deleteRecords(const sqlb::ObjectIdentifier& table, const QStri
if(pks.size() == 1)
{
statement = QString("DELETE FROM %1 WHERE %2 IN (%3);")
.arg(table.toString())
.arg(pks.at(0))
.arg(QString::fromStdString(table.toString()))
.arg(QString::fromStdString(pks.at(0)))
.arg(quoted_rowids.join(", "));
} else {
statement = QString("DELETE FROM %1 WHERE ").arg(table.toString());
statement = QString("DELETE FROM %1 WHERE ").arg(QString::fromStdString(table.toString()));
statement += "sqlb_make_single_value(";
for(const auto& pk : pks)
statement += sqlb::escapeIdentifier(pk) + ",";
statement += QString::fromStdString(sqlb::escapeIdentifier(pk)) + ",";
statement.chop(1);
statement += QString(") IN (%1)").arg(quoted_rowids.join(", "));
}
@@ -1377,33 +1385,33 @@ bool DBBrowserDB::deleteRecords(const sqlb::ObjectIdentifier& table, const QStri
}
}
bool DBBrowserDB::updateRecord(const sqlb::ObjectIdentifier& table, const QString& column,
const QString& rowid, const QByteArray& value, bool itsBlob, const std::vector<std::string>& pseudo_pk)
bool DBBrowserDB::updateRecord(const sqlb::ObjectIdentifier& table, const std::string& column,
const QString& rowid, const QByteArray& value, bool itsBlob, const sqlb::StringVector& pseudo_pk)
{
waitForDbRelease();
if (!isOpen()) return false;
// Get primary key of the object to edit.
QStringList pks = primaryKeyForEditing(table, pseudo_pk);
if(pks.isEmpty())
sqlb::StringVector pks = primaryKeyForEditing(table, pseudo_pk);
if(pks.empty())
{
lastErrorMessage = tr("Cannot set data on this object");
return false;
}
QString sql = QString("UPDATE %1 SET %2=? WHERE ")
.arg(table.toString())
.arg(sqlb::escapeIdentifier(column));
.arg(QString::fromStdString(table.toString()))
.arg(QString::fromStdString(sqlb::escapeIdentifier(column)));
// For a single rowid column we can use a simple WHERE condition, for multiple rowid columns we have to use sqlb_make_single_value to decode the composed rowid values.
if(pks.size() == 1)
{
sql += QString("%1='%2';")
.arg(sqlb::escapeIdentifier(pks.first()))
.arg(QString::fromStdString(sqlb::escapeIdentifier(pks.front())))
.arg(QString(rowid).replace("'", "''"));
} else {
sql += QString("sqlb_make_single_value(%1)='%2';")
.arg(sqlb::escapeIdentifier(pks).join(","))
.arg(QString::fromStdString(sqlb::joinStringVector(sqlb::escapeIdentifier(pks), ",")))
.arg(QString(rowid).replace("'", "''"));
}
@@ -1445,7 +1453,7 @@ bool DBBrowserDB::updateRecord(const sqlb::ObjectIdentifier& table, const QStrin
}
}
QStringList DBBrowserDB::primaryKeyForEditing(const sqlb::ObjectIdentifier& table, const std::vector<std::string>& pseudo_pk) const
sqlb::StringVector DBBrowserDB::primaryKeyForEditing(const sqlb::ObjectIdentifier& table, const sqlb::StringVector& pseudo_pk) const
{
// This function returns the primary key of the object to edit. For views we support 'pseudo' primary keys which must be specified manually.
// If no pseudo pk is specified we'll take the rowid column of the table instead. If this neither a table nor was a pseudo-PK specified,
@@ -1457,13 +1465,10 @@ QStringList DBBrowserDB::primaryKeyForEditing(const sqlb::ObjectIdentifier& tabl
if(tbl)
return tbl->rowidColumns();
} else {
QStringList ret;
for(const auto& col : pseudo_pk)
ret << QString::fromStdString(col);
return ret;
return pseudo_pk;
}
return QStringList();
return sqlb::StringVector();
}
bool DBBrowserDB::createTable(const sqlb::ObjectIdentifier& name, const sqlb::FieldVector& structure)
@@ -1474,18 +1479,18 @@ bool DBBrowserDB::createTable(const sqlb::ObjectIdentifier& name, const sqlb::Fi
table.fields.push_back(structure.at(i));
// Execute it and update the schema
return executeSQL(table.sql(name.schema()));
return executeSQL(QString::fromStdString(table.sql(name.schema())));
}
bool DBBrowserDB::addColumn(const sqlb::ObjectIdentifier& tablename, const sqlb::Field& field)
{
QString sql = QString("ALTER TABLE %1 ADD COLUMN %2").arg(tablename.toString()).arg(field.toString());
QString sql = QString("ALTER TABLE %1 ADD COLUMN %2").arg(QString::fromStdString(tablename.toString())).arg(QString::fromStdString(field.toString()));
// Execute it and update the schema
return executeSQL(sql);
}
bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb::Table& new_table, AlterTableTrackColumns track_columns, QString newSchemaName)
bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb::Table& new_table, AlterTableTrackColumns track_columns, std::string newSchemaName)
{
// This function is split into three different parts:
// Part 1 checks the arguments and prepares them for processing. It also prepares the transaction etc.
@@ -1497,21 +1502,21 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
//
// If no new schema name has been set, we just use the old schema name
if(newSchemaName.isNull())
if(newSchemaName.empty())
{
newSchemaName = tablename.schema();
// When renaming the table in the current schema, check if it doesn't exist already in there
if(tablename.name() != new_table.name() && getObjectByName(sqlb::ObjectIdentifier(newSchemaName, new_table.name())) != nullptr)
{
lastErrorMessage = tr("A table with the name '%1' already exists in schema '%2'.").arg(new_table.name()).arg(newSchemaName);
lastErrorMessage = tr("A table with the name '%1' already exists in schema '%2'.").arg(QString::fromStdString(new_table.name())).arg(QString::fromStdString(newSchemaName));
return false;
}
} else {
// We're moving the table to a different schema. So check first if it doesn't already exist in the new schema.
if(newSchemaName != tablename.schema() && getObjectByName(sqlb::ObjectIdentifier(newSchemaName, new_table.name())) != nullptr)
{
lastErrorMessage = tr("A table with the name '%1' already exists in schema '%2'.").arg(new_table.name()).arg(newSchemaName);
lastErrorMessage = tr("A table with the name '%1' already exists in schema '%2'.").arg(QString::fromStdString(new_table.name())).arg(QString::fromStdString(newSchemaName));
return false;
}
}
@@ -1520,7 +1525,7 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
sqlb::TablePtr old_table_ptr = getObjectByName<sqlb::Table>(tablename);
if(old_table_ptr == nullptr)
{
lastErrorMessage = tr("No table with name '%1' exists in schema '%2'.").arg(tablename.name()).arg(tablename.schema());
lastErrorMessage = tr("No table with name '%1' exists in schema '%2'.").arg(QString::fromStdString(tablename.name())).arg(QString::fromStdString(tablename.schema()));
return false;
}
sqlb::Table old_table = *old_table_ptr;
@@ -1528,7 +1533,7 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
// Check if tracked fields actually exist in the old table
for(const auto& old_name : track_columns.keys())
{
if(!old_name.isNull() && sqlb::findField(old_table, old_name) == old_table.fields.end())
if(!old_name.isNull() && sqlb::findField(old_table, old_name.toStdString()) == old_table.fields.end())
{
lastErrorMessage = tr("Cannot find column %1.").arg(old_name);
return false;
@@ -1539,17 +1544,17 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
// We do this before checking if all tracked fields are in the new table to make sure the following check includes them.
for(const auto& field : old_table.fields)
{
if(!track_columns.keys().contains(field.name()))
if(!track_columns.keys().contains(QString::fromStdString(field.name())))
{
// If a field isn't tracked, add it to the list and indicate explicitly that it has the same name in the new table
track_columns[field.name()] = field.name();
track_columns[QString::fromStdString(field.name())] = QString::fromStdString(field.name());
}
}
// Check if tracked fields actually exist in the new table
for(const auto& new_name : track_columns.values())
{
if(!new_name.isNull() && sqlb::findField(new_table, new_name) == new_table.fields.end())
if(!new_name.isNull() && sqlb::findField(new_table, new_name.toStdString()) == new_table.fields.end())
{
lastErrorMessage = tr("Cannot find column %1.").arg(new_name);
return false;
@@ -1598,7 +1603,7 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
// If so, we add that field. The reason for looping through the new table schema instead of the track_columns
// map is that this way we make sure to preserve their order which increases our chances that we are done after
// this step.
if(new_fields.contains(field.name()))
if(new_fields.contains(QString::fromStdString(field.name())))
{
if(!addColumn(sqlb::ObjectIdentifier(tablename.schema(), new_table.name()), field))
{
@@ -1622,7 +1627,7 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
if(!old_name.isNull() && !new_name.isNull() && new_name != old_name)
{
if(!executeSQL(QString("ALTER TABLE %1 RENAME COLUMN %2 TO %3;")
.arg(sqlb::ObjectIdentifier(tablename.schema(), new_table.name()).toString())
.arg(QString::fromStdString(sqlb::ObjectIdentifier(tablename.schema(), new_table.name()).toString()))
.arg(sqlb::escapeIdentifier(old_name))
.arg(sqlb::escapeIdentifier(new_name))))
{
@@ -1668,10 +1673,10 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
//
// Create a new table with the desired schema and a name that doesn't exist yet
QString new_table_name = new_table.name();
std::string new_table_name = new_table.name();
sqlb::Table new_table_with_random_name = new_table;
new_table_with_random_name.setName(generateTemporaryTableName(newSchemaName));
if(!executeSQL(new_table_with_random_name.sql(newSchemaName), true, true))
if(!executeSQL(QString::fromStdString(new_table_with_random_name.sql(newSchemaName)), true, true))
{
QString error(tr("Creating new table failed. DB says: %1").arg(lastErrorMessage));
revertToSavepoint(savepointName);
@@ -1680,8 +1685,8 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
}
// Assemble list of column names to copy from in the old table and list of column names to into into in the new table
QStringList copy_values_from;
QStringList copy_values_to;
sqlb::StringVector copy_values_from;
sqlb::StringVector copy_values_to;
for(const auto& from : track_columns.keys())
{
// Ignore new fields
@@ -1693,18 +1698,18 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
if(to.isNull())
continue;
copy_values_from.push_back(from);
copy_values_to.push_back(to);
copy_values_from.push_back(from.toStdString());
copy_values_to.push_back(to.toStdString());
}
// Copy the data from the old table to the new one
if(!executeSQL(QString("INSERT INTO %1.%2 (%3) SELECT %4 FROM %5.%6;")
.arg(sqlb::escapeIdentifier(newSchemaName))
.arg(sqlb::escapeIdentifier(new_table_with_random_name.name()))
.arg(sqlb::escapeIdentifier(copy_values_to).join(","))
.arg(sqlb::escapeIdentifier(copy_values_from).join(","))
.arg(sqlb::escapeIdentifier(tablename.schema()))
.arg(sqlb::escapeIdentifier(old_table.name()))))
.arg(QString::fromStdString(sqlb::escapeIdentifier(newSchemaName)))
.arg(QString::fromStdString(sqlb::escapeIdentifier(new_table_with_random_name.name())))
.arg(QString::fromStdString(sqlb::joinStringVector(sqlb::escapeIdentifier(copy_values_to), ",")))
.arg(QString::fromStdString(sqlb::joinStringVector(sqlb::escapeIdentifier(copy_values_from), ",")))
.arg(QString::fromStdString(sqlb::escapeIdentifier(tablename.schema())))
.arg(QString::fromStdString(sqlb::escapeIdentifier(old_table.name())))))
{
QString error(tr("Copying data to new table failed. DB says:\n%1").arg(lastErrorMessage));
revertToSavepoint(savepointName);
@@ -1737,12 +1742,12 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
// We're updating the field name. So search for it in the index and replace it whereever it is found
for(size_t i=0;i<idx->fields.size();i++)
{
if(idx->fields[i].name() == from)
idx->fields[i].setName(to);
if(idx->fields[i].name() == from.toStdString())
idx->fields[i].setName(to.toStdString());
}
} else {
// We're removing a field. So remove it from any indices, too.
while(sqlb::removeField(idx, from))
while(sqlb::removeField(idx, from.toStdString()))
;
}
}
@@ -1750,11 +1755,11 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
// Only try to add the index later if it has any columns remaining. Also use the new schema name here, too, to basically move
// any index that references the table to the same new schema as the table.
if(idx->fields.size())
otherObjectsSql << idx->sql(newSchemaName);
otherObjectsSql << QString::fromStdString(idx->sql(newSchemaName));
} else {
// If it's a view or a trigger we don't have any chance to corrections yet. Just store the statement as is and
// hope for the best.
otherObjectsSql << it->originalSql().trimmed() + ";";
otherObjectsSql << QString::fromStdString(it->originalSql()) + ";";
}
}
}
@@ -1768,7 +1773,7 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
setPragma("defer_foreign_keys", "1");
// Delete the old table
if(!executeSQL(QString("DROP TABLE %1.%2;").arg(sqlb::escapeIdentifier(tablename.schema())).arg(sqlb::escapeIdentifier(old_table.name())), true, true))
if(!executeSQL(QString("DROP TABLE %1.%2;").arg(QString::fromStdString(sqlb::escapeIdentifier(tablename.schema()))).arg(QString::fromStdString(sqlb::escapeIdentifier(old_table.name()))), true, true))
{
QString error(tr("Deleting old table failed. DB says: %1").arg(lastErrorMessage));
revertToSavepoint(savepointName);
@@ -1813,7 +1818,7 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb
return true;
}
bool DBBrowserDB::renameTable(const QString& schema, const QString& from_table, const QString& to_table)
bool DBBrowserDB::renameTable(const std::string& schema, const std::string& from_table, const std::string& to_table)
{
// Do nothing if table names are the same
if(from_table == to_table)
@@ -1821,10 +1826,10 @@ bool DBBrowserDB::renameTable(const QString& schema, const QString& from_table,
// Check if table names only differ in case. If they do, we have to rename the table twice because SQLite can't rename 'table' to 'Table'.
// To solve this we rename 'table' to 'some temp name' and then 'some temp name' to 'Table'.
if(from_table.compare(to_table, Qt::CaseInsensitive) == 0)
if(compare_ci(from_table, to_table))
{
// Generate a temporary table name and rename the table via that by recusrively calling this function
QString temp_name = generateTemporaryTableName(schema);
std::string temp_name = generateTemporaryTableName(schema);
if(!renameTable(schema, from_table, temp_name))
return false;
if(!renameTable(schema, temp_name, to_table))
@@ -1838,13 +1843,13 @@ bool DBBrowserDB::renameTable(const QString& schema, const QString& from_table,
// Rename the table
QString sql = QString("ALTER TABLE %1.%2 RENAME TO %3")
.arg(sqlb::escapeIdentifier(schema))
.arg(sqlb::escapeIdentifier(from_table))
.arg(sqlb::escapeIdentifier(to_table));
.arg(QString::fromStdString(sqlb::escapeIdentifier(schema)))
.arg(QString::fromStdString(sqlb::escapeIdentifier(from_table)))
.arg(QString::fromStdString(sqlb::escapeIdentifier(to_table)));
if(!executeSQL(sql))
{
QString error = tr("Error renaming table '%1' to '%2'."
"Message from database engine:\n%3").arg(from_table).arg(to_table).arg(lastErrorMessage);
"Message from database engine:\n%3").arg(QString::fromStdString(from_table)).arg(QString::fromStdString(to_table)).arg(lastErrorMessage);
lastErrorMessage = error;
qWarning() << lastErrorMessage;
return false;
@@ -1853,7 +1858,7 @@ bool DBBrowserDB::renameTable(const QString& schema, const QString& from_table,
}
}
objectMap DBBrowserDB::getBrowsableObjects(const QString& schema) const
objectMap DBBrowserDB::getBrowsableObjects(const std::string& schema) const
{
objectMap res;
@@ -1910,7 +1915,7 @@ void DBBrowserDB::updateSchema()
while(sqlite3_step(db_vm) == SQLITE_ROW)
{
// Get the schema name which is in column 1 (counting starts with 0). 0 contains an ID and 2 the file path.
QString schema_name = QString::fromUtf8(reinterpret_cast<const char*>(sqlite3_column_text(db_vm, 1)));
std::string schema_name = reinterpret_cast<const char*>(sqlite3_column_text(db_vm, 1));
// Always add the schema to the map. This makes sure it's even then added when there are no objects in the database
schemata[schema_name] = objectMap();
@@ -1921,7 +1926,7 @@ void DBBrowserDB::updateSchema()
if(schema_name == "temp")
statement = QString("SELECT type,name,sql,tbl_name FROM sqlite_temp_master;");
else
statement = QString("SELECT type,name,sql,tbl_name FROM %1.sqlite_master;").arg(sqlb::escapeIdentifier(schema_name));
statement = QString("SELECT type,name,sql,tbl_name FROM %1.sqlite_master;").arg(QString::fromStdString(sqlb::escapeIdentifier(schema_name)));
QByteArray utf8Statement = statement.toUtf8();
logSQL(statement, kLogMsg_App);
@@ -1931,23 +1936,23 @@ void DBBrowserDB::updateSchema()
{
while(sqlite3_step(vm) == SQLITE_ROW)
{
QString val_type = QString::fromUtf8(reinterpret_cast<const char*>(sqlite3_column_text(vm, 0)));
QString val_name = QString::fromUtf8(reinterpret_cast<const char*>(sqlite3_column_text(vm, 1)));
std::string val_type = reinterpret_cast<const char*>(sqlite3_column_text(vm, 0));
std::string val_name = reinterpret_cast<const char*>(sqlite3_column_text(vm, 1));
QString val_sql = QString::fromUtf8(reinterpret_cast<const char*>(sqlite3_column_text(vm, 2)));
QString val_tblname = QString::fromUtf8(reinterpret_cast<const char*>(sqlite3_column_text(vm, 3)));
val_sql.replace("\r", "");
std::string val_tblname = reinterpret_cast<const char*>(sqlite3_column_text(vm, 3));
val_sql = val_sql.replace("\r", "");
if(!val_sql.isEmpty())
{
sqlb::ObjectPtr object;
if(val_type == "table")
object = sqlb::Table::parseSQL(val_sql);
object = sqlb::Table::parseSQL(val_sql.toStdString());
else if(val_type == "index")
object = sqlb::Index::parseSQL(val_sql);
object = sqlb::Index::parseSQL(val_sql.toStdString());
else if(val_type == "trigger")
object = sqlb::Trigger::parseSQL(val_sql);
object = sqlb::Trigger::parseSQL(val_sql.toStdString());
else if(val_type == "view")
object = sqlb::View::parseSQL(val_sql);
object = sqlb::View::parseSQL(val_sql.toStdString());
else
continue;
@@ -2105,12 +2110,12 @@ void DBBrowserDB::loadExtensionsFromSettings()
}
}
QVector<QPair<QString, QString>> DBBrowserDB::queryColumnInformation(const QString& schema_name, const QString& object_name)
std::vector<std::pair<std::string, std::string>> DBBrowserDB::queryColumnInformation(const std::string& schema_name, const std::string& object_name)
{
waitForDbRelease();
QVector<QPair<QString, QString>> result;
QString statement = QString("PRAGMA %1.TABLE_INFO(%2);").arg(sqlb::escapeIdentifier(schema_name)).arg(sqlb::escapeIdentifier(object_name));
std::vector<std::pair<std::string, std::string>> result;
QString statement = QString("PRAGMA %1.TABLE_INFO(%2);").arg(QString::fromStdString(sqlb::escapeIdentifier(schema_name))).arg(QString::fromStdString(sqlb::escapeIdentifier(object_name)));
logSQL(statement, kLogMsg_App);
sqlite3_stmt* vm;
@@ -2119,10 +2124,10 @@ QVector<QPair<QString, QString>> DBBrowserDB::queryColumnInformation(const QStri
{
while(sqlite3_step(vm) == SQLITE_ROW)
{
QString name = QString::fromUtf8(reinterpret_cast<const char*>(sqlite3_column_text(vm, 1)));
QString type = QString::fromUtf8(reinterpret_cast<const char*>(sqlite3_column_text(vm, 2)));
std::string name = reinterpret_cast<const char*>(sqlite3_column_text(vm, 1));
std::string type = reinterpret_cast<const char*>(sqlite3_column_text(vm, 2));
result.push_back(qMakePair(name, type));
result.push_back(std::make_pair(name, type));
}
sqlite3_finalize(vm);
} else{
@@ -2138,7 +2143,7 @@ QString DBBrowserDB::generateSavepointName(const QString& identifier) const
return QString("db4s_%1_%2").arg(identifier).arg(QDateTime::currentMSecsSinceEpoch());
}
QString DBBrowserDB::generateTemporaryTableName(const QString& schema) const
std::string DBBrowserDB::generateTemporaryTableName(const std::string& schema) const
{
// We're using a static variable as a counter here instead of checking from the beginning onwards every time. This has
// two reasons: 1) It makes the function thread-safe, and 2) it saves us some time because in case older temporary tables
@@ -2147,7 +2152,7 @@ QString DBBrowserDB::generateTemporaryTableName(const QString& schema) const
while(true)
{
QString table_name = QString("sqlb_temp_table_%1").arg(++counter);
std::string table_name = "sqlb_temp_table_" + std::to_string(++counter);
if(!getObjectByName(sqlb::ObjectIdentifier(schema, table_name)))
return table_name;
}
+19 -12
View File
@@ -7,7 +7,9 @@
#include <memory>
#include <mutex>
#include <functional>
#include <vector>
#include <QObject>
#include <QByteArray>
#include <QMultiMap>
#include <QStringList>
@@ -22,11 +24,16 @@ enum LogMessageType
kLogMsg_ErrorLog
};
typedef QMultiMap<QString, sqlb::ObjectPtr> objectMap; // Maps from object type (table, index, view, trigger) to a pointer to the object representation
typedef QMap<QString, objectMap> schemaMap; // Maps from the schema name (main, temp, attached schemas) to the object map for that schema
typedef QMultiMap<std::string, sqlb::ObjectPtr> objectMap; // Maps from object type (table, index, view, trigger) to a pointer to the object representation
typedef QMap<std::string, objectMap> schemaMap; // Maps from the schema name (main, temp, attached schemas) to the object map for that schema
int collCompare(void* pArg, int sizeA, const void* sA, int sizeB, const void* sB);
namespace sqlb
{
QString escapeIdentifier(const QString& id);
}
/// represents a single SQLite database. except when noted otherwise,
/// all member functions are to be called from the main UI thread
/// only.
@@ -132,7 +139,7 @@ public:
* @param rowdata A list of QByteArray containing the row data.
* @return true if statement execution was ok, else false.
*/
bool getRow(const sqlb::ObjectIdentifier& table, const QString& rowid, QVector<QByteArray>& rowdata);
bool getRow(const sqlb::ObjectIdentifier& table, const QString& rowid, std::vector<QByteArray>& rowdata);
/**
* @brief Interrupts the currenty running statement as soon as possible.
@@ -160,15 +167,15 @@ private:
* @param pk_value This optional parameter can be used to manually set a specific value for the primary key column
* @return An sqlite conform INSERT INTO statement with empty values. (NULL,'',0)
*/
QString emptyInsertStmt(const QString& schemaName, const sqlb::Table& t, const QString& pk_value = QString()) const;
QString emptyInsertStmt(const std::string& schemaName, const sqlb::Table& t, const QString& pk_value = QString()) const;
public:
QString addRecord(const sqlb::ObjectIdentifier& tablename);
bool deleteRecords(const sqlb::ObjectIdentifier& table, const QStringList& rowids, const std::vector<std::string>& pseudo_pk = {});
bool updateRecord(const sqlb::ObjectIdentifier& table, const QString& column, const QString& rowid, const QByteArray& value, bool itsBlob, const std::vector<std::string>& pseudo_pk = {});
bool deleteRecords(const sqlb::ObjectIdentifier& table, const QStringList& rowids, const sqlb::StringVector& pseudo_pk = {});
bool updateRecord(const sqlb::ObjectIdentifier& table, const std::string& column, const QString& rowid, const QByteArray& value, bool itsBlob, const sqlb::StringVector& pseudo_pk = {});
bool createTable(const sqlb::ObjectIdentifier& name, const sqlb::FieldVector& structure);
bool renameTable(const QString& schema, const QString& from_table, const QString& to_table);
bool renameTable(const std::string& schema, const std::string& from_table, const std::string& to_table);
bool addColumn(const sqlb::ObjectIdentifier& tablename, const sqlb::Field& field);
/**
@@ -190,9 +197,9 @@ public:
* @param newSchema Set this to a non-empty string to move the table to a new schema
* @return true if renaming was successful, false if not. In the latter case also lastErrorMessage is set
*/
bool alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb::Table& new_table, AlterTableTrackColumns track_columns, QString newSchemaName = QString());
bool alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb::Table& new_table, AlterTableTrackColumns track_columns, std::string newSchemaName = "");
objectMap getBrowsableObjects(const QString& schema) const;
objectMap getBrowsableObjects(const std::string& schema) const;
template<typename T = sqlb::Object>
const std::shared_ptr<T> getObjectByName(const sqlb::ObjectIdentifier& name) const
@@ -225,13 +232,13 @@ public:
static QStringList Datatypes;
private:
QVector<QPair<QString, QString>> queryColumnInformation(const QString& schema_name, const QString& object_name);
std::vector<std::pair<std::string, std::string> > queryColumnInformation(const std::string& schema_name, const std::string& object_name);
public:
QString generateSavepointName(const QString& identifier = QString()) const;
// This function generates the name for a temporary table. It guarantees that there is no table with this name yet
QString generateTemporaryTableName(const QString& schema) const;
std::string generateTemporaryTableName(const std::string& schema) const;
schemaMap schemata;
@@ -261,7 +268,7 @@ private:
bool isEncrypted;
bool isReadOnly;
QStringList primaryKeyForEditing(const sqlb::ObjectIdentifier& table, const std::vector<std::string>& pseudo_pk) const;
sqlb::StringVector primaryKeyForEditing(const sqlb::ObjectIdentifier& table, const sqlb::StringVector& pseudo_pk) const;
// SQLite Callbacks
void collationNeeded(void* pData, sqlite3* db, int eTextRep, const char* sCollationName);
+37 -44
View File
@@ -74,7 +74,7 @@ void SqliteTableModel::handleFinishedFetch (int life_id, unsigned int fetched_ro
if(fetched_row_end != fetched_row_begin)
{
// TODO optimize
int num_columns = m_headers.size();
size_t num_columns = m_headers.size();
emit dataChanged(createIndex(fetched_row_begin, 0), createIndex(fetched_row_end - 1, num_columns - 1));
}
@@ -132,13 +132,11 @@ void SqliteTableModel::setQuery(const sqlb::Query& query)
sqlb::TablePtr t = m_db.getObjectByName<sqlb::Table>(query.table());
if(t && t->fields.size()) // parsing was OK
{
QStringList rowids = t->rowidColumns();
std::vector<std::string> rowids_std;
for(const auto& rowid : rowids)
rowids_std.push_back(rowid.toStdString());
m_query.setRowIdColumns(rowids_std);
m_headers.push_back(rowids.join(","));
m_headers.append(t->fieldNames());
sqlb::StringVector rowids = t->rowidColumns();
m_query.setRowIdColumns(rowids);
m_headers.push_back(sqlb::joinStringVector(rowids, ","));
for(const auto& n : t->fieldNames())
m_headers.push_back(n);
// parse columns types
static QStringList dataTypes = QStringList()
@@ -148,7 +146,7 @@ void SqliteTableModel::setQuery(const sqlb::Query& query)
<< "BLOB";
for(const sqlb::Field& fld : t->fields)
{
QString name(fld.type().toUpper());
QString name = QString::fromStdString(fld.type()).toUpper();
int colType = dataTypes.indexOf(name);
colType = (colType == -1) ? SQLITE_TEXT : colType + 1;
m_vDataTypes.push_back(colType);
@@ -162,18 +160,16 @@ void SqliteTableModel::setQuery(const sqlb::Query& query)
// NOTE: It would be nice to eventually get rid of this piece here. As soon as the grammar parser is good enough...
if(!allOk)
{
QString sColumnQuery = QString::fromUtf8("SELECT * FROM %1;").arg(query.table().toString());
QString sColumnQuery = QString::fromUtf8("SELECT * FROM %1;").arg(QString::fromStdString(query.table().toString()));
if(m_query.rowIdColumns().empty())
m_query.setRowIdColumn("_rowid_");
m_headers.push_back("_rowid_");
m_headers.append(getColumns(nullptr, sColumnQuery, m_vDataTypes));
auto columns = getColumns(nullptr, sColumnQuery, m_vDataTypes);
m_headers.insert(m_headers.end(), columns.begin(), columns.end());
}
// Tell the query object about the column names
std::vector<std::string> column_names;
for(const auto& h : m_headers)
column_names.push_back(h.toStdString());
m_query.setColumNames(column_names);
m_query.setColumNames(m_headers);
// Apply new query and update view
buildQuery();
@@ -197,7 +193,10 @@ void SqliteTableModel::setQuery(const QString& sQuery, const QString& sCountQuer
worker->triggerRowCountDetermination(m_lifeCounter);
if(!dontClearHeaders)
m_headers.append(getColumns(worker->getDb(), sQuery, m_vDataTypes));
{
auto columns = getColumns(worker->getDb(), sQuery, m_vDataTypes);
m_headers.insert(m_headers.end(), columns.begin(), columns.end());
}
// now fetch the first entries
triggerCacheLoad(static_cast<int>(m_chunkSize / 2) - 1);
@@ -212,7 +211,7 @@ int SqliteTableModel::rowCount(const QModelIndex&) const
int SqliteTableModel::columnCount(const QModelIndex&) const
{
return m_headers.size();
return static_cast<int>(m_headers.size());
}
size_t SqliteTableModel::filterCount() const
@@ -246,18 +245,18 @@ QVariant SqliteTableModel::headerData(int section, Qt::Orientation orientation,
if (orientation == Qt::Horizontal)
{
// if we have a VIRTUAL table the model will not be valid, with no header data
if(section < m_headers.size()) {
if(static_cast<size_t>(section) < m_headers.size()) {
QString sortIndicator;
for(size_t i = 0; i < m_query.orderBy().size(); i++) {
const sqlb::SortedColumn sortedColumn = m_query.orderBy()[i];
// Append sort indicator with direction and ordinal number in superscript style
if (sortedColumn.column == section) {
if (sortedColumn.column == static_cast<size_t>(section)) {
sortIndicator = sortedColumn.direction == sqlb::Ascending ? "" : "";
sortIndicator.append(toSuperScript(i+1));
break;
}
}
return m_headers.at(section) + sortIndicator;
return QString::fromStdString(m_headers.at(static_cast<size_t>(section))) + sortIndicator;
}
return QString("%1").arg(section + 1);
}
@@ -373,8 +372,10 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
} else if(role == Qt::ToolTipRole) {
sqlb::ForeignKeyClause fk = getForeignKeyClause(index.column()-1);
if(fk.isSet())
return tr("References %1(%2)\nHold %3Shift and click to jump there").arg(fk.table()).arg(fk.columns().join(","))
.arg(QKeySequence(Qt::CTRL).toString(QKeySequence::NativeText));
return tr("References %1(%2)\nHold %3Shift and click to jump there")
.arg(QString::fromStdString(fk.table()))
.arg(QString::fromStdString(sqlb::joinStringVector(fk.columns(), ",")))
.arg(QKeySequence(Qt::CTRL).toString(QKeySequence::NativeText));
else
return QString();
}
@@ -460,12 +461,9 @@ bool SqliteTableModel::setTypedData(const QModelIndex& index, bool isBlob, const
if(m_db.updateRecord(m_query.table(), m_headers.at(index.column()), cached_row.at(0), newValue, isBlob, m_query.rowIdColumns()))
{
cached_row.replace(index.column(), newValue);
QStringList header;
for(const auto& col : m_query.rowIdColumns())
header += QString::fromStdString(col);
if(m_headers.at(index.column()) == header.join(",")) {
cached_row.replace(0, newValue);
cached_row[index.column()] = newValue;
if(m_headers.at(index.column()) == sqlb::joinStringVector(m_query.rowIdColumns(), ",")) {
cached_row[0] = newValue;
const QModelIndex& rowidIndex = index.sibling(index.row(), 0);
lock.unlock();
emit dataChanged(rowidIndex, rowidIndex);
@@ -530,7 +528,7 @@ SqliteTableModel::Row SqliteTableModel::makeDefaultCacheEntry () const
{
Row blank_data;
for(int i=0; i < m_headers.size(); ++i)
for(size_t i=0; i < m_headers.size(); ++i)
blank_data.push_back("");
return blank_data;
@@ -562,15 +560,15 @@ bool SqliteTableModel::insertRows(int row, int count, const QModelIndex& parent)
return false;
}
tempList.push_back(blank_data);
tempList.back().replace(0, rowid.toUtf8());
tempList.back()[0] = rowid.toUtf8();
// update column with default values
Row rowdata;
if(m_db.getRow(m_query.table(), rowid, rowdata))
{
for(int j=1; j < m_headers.size(); ++j)
for(size_t j=1; j < m_headers.size(); ++j)
{
tempList.back().replace(j, rowdata[j - 1]);
tempList.back()[j] = rowdata[j - 1];
}
}
}
@@ -633,7 +631,7 @@ QModelIndex SqliteTableModel::dittoRecord(int old_row)
sqlb::TablePtr t = m_db.getObjectByName<sqlb::Table>(m_query.table());
QStringList pk = t->primaryKey();
sqlb::StringVector pk = t->primaryKey();
for (size_t col = 0; col < t->fields.size(); ++col) {
if(!contains(pk, t->fields.at(col).name())) {
if (!firstEditedColumn)
@@ -716,7 +714,7 @@ void SqliteTableModel::removeCommentsFromQuery(QString& query)
}
}
QStringList SqliteTableModel::getColumns(std::shared_ptr<sqlite3> pDb, const QString& sQuery, QVector<int>& fieldsTypes)
std::vector<std::string> SqliteTableModel::getColumns(std::shared_ptr<sqlite3> pDb, const QString& sQuery, std::vector<int>& fieldsTypes)
{
if(!pDb)
pDb = m_db.get(tr("retrieving list of columns"));
@@ -724,14 +722,14 @@ QStringList SqliteTableModel::getColumns(std::shared_ptr<sqlite3> pDb, const QSt
sqlite3_stmt* stmt;
QByteArray utf8Query = sQuery.toUtf8();
int status = sqlite3_prepare_v2(pDb.get(), utf8Query, utf8Query.size(), &stmt, nullptr);
QStringList listColumns;
std::vector<std::string> listColumns;
if(SQLITE_OK == status)
{
sqlite3_step(stmt);
int columns = sqlite3_data_count(stmt);
for(int i = 0; i < columns; ++i)
{
listColumns.append(QString::fromUtf8(sqlite3_column_name(stmt, i)));
listColumns.push_back(sqlite3_column_name(stmt, i));
fieldsTypes.push_back(sqlite3_column_type(stmt, i));
}
}
@@ -742,11 +740,11 @@ QStringList SqliteTableModel::getColumns(std::shared_ptr<sqlite3> pDb, const QSt
void SqliteTableModel::addCondFormat(int column, const CondFormat& condFormat)
{
m_mCondFormats[column].append(condFormat);
m_mCondFormats[column].push_back(condFormat);
emit layoutChanged();
}
void SqliteTableModel::setCondFormats(int column, const QVector<CondFormat>& condFormats)
void SqliteTableModel::setCondFormats(int column, const std::vector<CondFormat>& condFormats)
{
m_mCondFormats[column] = condFormats;
emit layoutChanged();
@@ -849,12 +847,7 @@ void SqliteTableModel::setPseudoPk(std::vector<std::string> pseudoPk)
m_query.setRowIdColumns(pseudoPk);
if(m_headers.size())
{
QStringList headers;
for(const auto& col : pseudoPk)
headers << QString::fromStdString(col);
m_headers[0] = headers.join(",");
}
m_headers[0] = sqlb::joinStringVector(pseudoPk, ",");
buildQuery();
}
+7 -8
View File
@@ -2,11 +2,10 @@
#define SQLITETABLEMODEL_H
#include <QAbstractTableModel>
#include <QStringList>
#include <QVector>
#include <QMutex>
#include <QColor>
#include <memory>
#include <vector>
#include "RowCache.h"
#include "CondFormat.h"
@@ -114,7 +113,7 @@ public:
static void removeCommentsFromQuery(QString& query);
void addCondFormat(int column, const CondFormat& condFormat);
void setCondFormats(int column, const QVector<CondFormat>& condFormats);
void setCondFormats(int column, const std::vector<CondFormat>& condFormats);
DBBrowserDB& db() { return m_db; }
@@ -143,7 +142,7 @@ private:
void buildQuery();
/// \param pDb connection to query; if null, obtains it from 'm_db'.
QStringList getColumns(std::shared_ptr<sqlite3> pDb, const QString& sQuery, QVector<int>& fieldsTypes);
std::vector<std::string> getColumns(std::shared_ptr<sqlite3> pDb, const QString& sQuery, std::vector<int>& fieldsTypes);
QByteArray encode(const QByteArray& str) const;
QByteArray decode(const QByteArray& str) const;
@@ -167,13 +166,13 @@ private:
RowCount m_rowCountAvailable;
unsigned int m_currentRowCount;
QStringList m_headers;
std::vector<std::string> m_headers;
/// reading something in background right now? (either counting
/// rows or actually loading data, doesn't matter)
bool readingData() const;
using Row = QVector<QByteArray>;
using Row = std::vector<QByteArray>;
mutable RowCache<Row> m_cache;
Row makeDefaultCacheEntry () const;
@@ -181,8 +180,8 @@ private:
bool nosync_isBinary(const QModelIndex& index) const;
QString m_sQuery;
QVector<int> m_vDataTypes;
QMap<int, QVector<CondFormat>> m_mCondFormats;
std::vector<int> m_vDataTypes;
QMap<int, std::vector<CondFormat>> m_mCondFormats;
sqlb::Query m_query;
/**
+25 -19
View File
@@ -4,7 +4,7 @@
#include <QtTest/QTest>
#include <QCoreApplication>
#include <QTextStream>
#include <QVector>
#include <vector>
#include "csvparser.h"
#include "TestImport.h"
@@ -27,7 +27,7 @@ void TestImport::csvImport()
QFETCH(char, quote);
QFETCH(QString, encoding);
QFETCH(int, numfields);
QFETCH(QVector<QVector<QByteArray>>, result);
QFETCH(std::vector<std::vector<QByteArray>>, result);
// Create temporary CSV file
QTemporaryFile file;
@@ -44,10 +44,10 @@ void TestImport::csvImport()
QTextStream tstream(&file);
tstream.setCodec(encoding.toUtf8());
QVector<QVector<QByteArray>> parsedCsv;
std::vector<std::vector<QByteArray>> parsedCsv;
int parsedCsvColumns = 0;
csvparser.parse([&parsedCsv, &parsedCsvColumns](size_t /*rowNum*/, const CSVRow& data) -> bool {
QVector<QByteArray> row;
std::vector<QByteArray> row;
for(size_t i=0;i<data.num_fields;i++)
row.push_back(QByteArray(data.fields[i].data, data.fields[i].data_length));
parsedCsv.push_back(row);
@@ -75,12 +75,13 @@ void TestImport::csvImport_data()
QTest::addColumn<char>("quote");
QTest::addColumn<QString>("encoding");
QTest::addColumn<int>("numfields");
QTest::addColumn<QVector<QVector<QByteArray>>>("result");
QTest::addColumn<std::vector<std::vector<QByteArray>>>("result");
QVector<QVector<QByteArray>> result;
result.append(QVector<QByteArray>() << "a" << "b" << "c");
result.append(QVector<QByteArray>() << "d" << "e" << "f");
result.append(QVector<QByteArray>() << "g" << "h" << "i");
std::vector<std::vector<QByteArray>> result{
{"a", "b", "c"},
{"d", "e", "f"},
{"g", "h", "i"}
};
QTest::newRow("commas_noquotes") << "a,b,c\nd,e,f\ng,h,i\n"
<< ','
<< static_cast<char>(0)
@@ -119,11 +120,13 @@ void TestImport::csvImport_data()
<< result;
result.clear();
result.append(QVector<QByteArray>() << "a" << "b" << "");
result.append(QVector<QByteArray>() << "c" << "");
result.append(QVector<QByteArray>() << "d" << "" << "e");
result.append(QVector<QByteArray>() << "");
result.append(QVector<QByteArray>() << "" << "" << "f");
result = {
{"a", "b", ""},
{"c", ""},
{"d", "", "e"},
{""},
{"", "", "f"}
};
QTest::newRow("emptyvalues") << "a,b,\nc,\nd,,e\n\n,,f"
<< ','
<< static_cast<char>(0)
@@ -132,7 +135,7 @@ void TestImport::csvImport_data()
<< result;
result.clear();
result.append(QVector<QByteArray>() << "a" << "b" << "c");
result = {{"a", "b", "c"}};
QTest::newRow("oneline") << "a,b,c"
<< ','
<< static_cast<char>(0)
@@ -141,8 +144,11 @@ void TestImport::csvImport_data()
<< result;
result.clear();
result.append(QVector<QByteArray>() << "a,a\"" << "b" << "c");
result.append(QVector<QByteArray>() << "d" << "e" << "\"\"f,f");
result = {
{"a,a\"", "b", "c"},
{"d", "e", "\"\"f,f"}
};
QTest::newRow("manyquotes") << "\"a,a\"\"\",\"b\",\"c\"\n\"d\",\"e\",\"\"\"\"\"f,f\"\n"
<< ','
<< '"'
@@ -151,7 +157,7 @@ void TestImport::csvImport_data()
<< result;
result.clear();
result.append(QVector<QByteArray>() << QByteArray("\xC2\xAE") << QByteArray("\xC9\x85") << QByteArray("\xC6\x89"));
result = {{QByteArray("\xC2\xAE"), QByteArray("\xC9\x85"), QByteArray("\xC6\x89")}};
QString csv = QString::fromUtf8("\xC2\xAE") + "," + QString::fromUtf8("\xC9\x85") + "," + QString::fromUtf8("\xC6\x89") + "\n";
QTest::newRow("utf8chars") << csv
<< ','
@@ -161,7 +167,7 @@ void TestImport::csvImport_data()
<< result;
result.clear();
result.append(QVector<QByteArray>() << QByteArray("\u4E18") << QByteArray("\u4E26") << QByteArray("\u4E4B"));
result = {{QByteArray("\u4E18"), QByteArray("\u4E26"), QByteArray("\u4E4B")}};
QString csv2 = QString::fromUtf8("\u4E18") + "," + QString::fromUtf8("\u4E26") + "," + QString::fromUtf8("\u4E4B") + "\n";
QTest::newRow("utf16chars") << csv2
<< ','
+155 -155
View File
@@ -30,12 +30,12 @@ void TestTable::sqlOutput()
tt.fields.push_back(fkm);
tt.addConstraint({f.name(), fkm.name()}, ConstraintPtr(new PrimaryKeyConstraint()));
QCOMPARE(tt.sql(), QString("CREATE TABLE \"testtable\" (\n"
"\t\"id\"\tinteger,\n"
"\t\"car\"\ttext,\n"
"\t\"km\"\tinteger CHECK(km > 1000),\n"
"\tPRIMARY KEY(\"id\",\"km\")\n"
");"));
QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n"
"\t\"id\"\tinteger,\n"
"\t\"car\"\ttext,\n"
"\t\"km\"\tinteger CHECK(km > 1000),\n"
"\tPRIMARY KEY(\"id\",\"km\")\n"
");");
}
void TestTable::sqlGraveAccentOutput()
@@ -49,12 +49,12 @@ void TestTable::sqlGraveAccentOutput()
tt.addConstraint({f.name(), fkm.name()}, ConstraintPtr(new PrimaryKeyConstraint()));
sqlb::setIdentifierQuoting(sqlb::GraveAccents);
QCOMPARE(tt.sql(), QString("CREATE TABLE `testtable` (\n"
"\t`id`\tinteger,\n"
"\t`car`\ttext,\n"
"\t`km`\tinteger CHECK(km > 1000),\n"
"\tPRIMARY KEY(`id`,`km`)\n"
");"));
QCOMPARE(tt.sql(), "CREATE TABLE `testtable` (\n"
"\t`id`\tinteger,\n"
"\t`car`\ttext,\n"
"\t`km`\tinteger CHECK(km > 1000),\n"
"\tPRIMARY KEY(`id`,`km`)\n"
");");
sqlb::setIdentifierQuoting(sqlb::DoubleQuotes);
}
@@ -71,12 +71,12 @@ void TestTable::sqlSquareBracketsOutput()
tt.addConstraint({f.name(), fkm.name()}, ConstraintPtr(new PrimaryKeyConstraint()));
sqlb::setIdentifierQuoting(sqlb::SquareBrackets);
QCOMPARE(tt.sql(), QString("CREATE TABLE [testtable] (\n"
"\t[id]\tinteger,\n"
"\t[car]\ttext,\n"
"\t[km]\tinteger CHECK(km > 1000),\n"
"\tPRIMARY KEY([id],[km])\n"
");"));
QCOMPARE(tt.sql(), "CREATE TABLE [testtable] (\n"
"\t[id]\tinteger,\n"
"\t[car]\ttext,\n"
"\t[km]\tinteger CHECK(km > 1000),\n"
"\tPRIMARY KEY([id],[km])\n"
");");
sqlb::setIdentifierQuoting(sqlb::DoubleQuotes);
}
@@ -92,11 +92,11 @@ void TestTable::autoincrement()
tt.fields.push_back(fkm);
tt.addConstraint({f.name()}, ConstraintPtr(new PrimaryKeyConstraint()));
QCOMPARE(tt.sql(), QString("CREATE TABLE \"testtable\" (\n"
"\t\"id\"\tinteger PRIMARY KEY AUTOINCREMENT,\n"
"\t\"car\"\ttext,\n"
"\t\"km\"\tinteger\n"
");"));
QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n"
"\t\"id\"\tinteger PRIMARY KEY AUTOINCREMENT,\n"
"\t\"car\"\ttext,\n"
"\t\"km\"\tinteger\n"
");");
}
void TestTable::notnull()
@@ -110,11 +110,11 @@ void TestTable::notnull()
tt.fields.push_back(fkm);
tt.addConstraint({f.name()}, ConstraintPtr(new PrimaryKeyConstraint()));
QCOMPARE(tt.sql(), QString("CREATE TABLE \"testtable\" (\n"
"\t\"id\"\tinteger PRIMARY KEY AUTOINCREMENT,\n"
"\t\"car\"\ttext NOT NULL,\n"
"\t\"km\"\tinteger\n"
");"));
QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n"
"\t\"id\"\tinteger PRIMARY KEY AUTOINCREMENT,\n"
"\t\"car\"\ttext NOT NULL,\n"
"\t\"km\"\tinteger\n"
");");
}
void TestTable::withoutRowid()
@@ -127,10 +127,10 @@ void TestTable::withoutRowid()
tt.setWithoutRowidTable(true);
tt.addConstraint({f.name()}, ConstraintPtr(new PrimaryKeyConstraint()));
QCOMPARE(tt.sql(), QString("CREATE TABLE \"testtable\" (\n"
"\t\"a\"\tinteger PRIMARY KEY AUTOINCREMENT,\n"
"\t\"b\"\tinteger\n"
") WITHOUT ROWID;"));
QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n"
"\t\"a\"\tinteger PRIMARY KEY AUTOINCREMENT,\n"
"\t\"b\"\tinteger\n"
") WITHOUT ROWID;");
}
void TestTable::foreignKeys()
@@ -138,12 +138,12 @@ void TestTable::foreignKeys()
Table tt("testtable");
Field f("a", "integer");
tt.fields.push_back(f);
tt.addConstraint({f.name()}, sqlb::ConstraintPtr(new sqlb::ForeignKeyClause("b", QStringList("c"))));
tt.addConstraint({f.name()}, sqlb::ConstraintPtr(new sqlb::ForeignKeyClause("b", sqlb::StringVector{"c"})));
QCOMPARE(tt.sql(), QString("CREATE TABLE \"testtable\" (\n"
"\t\"a\"\tinteger,\n"
"\tFOREIGN KEY(\"a\") REFERENCES \"b\"(\"c\")\n"
");"));
QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n"
"\t\"a\"\tinteger,\n"
"\tFOREIGN KEY(\"a\") REFERENCES \"b\"(\"c\")\n"
");");
}
void TestTable::uniqueConstraint()
@@ -158,21 +158,21 @@ void TestTable::uniqueConstraint()
tt.fields.push_back(f3);
tt.addConstraint({f2.name(), f3.name()}, sqlb::ConstraintPtr(new sqlb::UniqueConstraint()));
QCOMPARE(tt.sql(), QString("CREATE TABLE \"testtable\" (\n"
"\t\"a\"\tinteger UNIQUE,\n"
"\t\"b\"\tinteger,\n"
"\t\"c\"\tinteger,\n"
"\tUNIQUE(\"b\",\"c\")\n"
");"));
QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n"
"\t\"a\"\tinteger UNIQUE,\n"
"\t\"b\"\tinteger,\n"
"\t\"c\"\tinteger,\n"
"\tUNIQUE(\"b\",\"c\")\n"
");");
}
void TestTable::parseSQL()
{
QString sSQL = "create TABLE hero (\n"
"\tid integer PRIMARY KEY AUTOINCREMENT,\n"
"\tname text NOT NULL DEFAULT 'xxxx',\n"
"\tinfo VARCHAR(255) CHECK (info == 'x')\n"
");";
std::string sSQL = "create TABLE hero (\n"
"\tid integer PRIMARY KEY AUTOINCREMENT,\n"
"\tname text NOT NULL DEFAULT 'xxxx',\n"
"\tinfo VARCHAR(255) CHECK (info == 'x')\n"
");";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
@@ -184,59 +184,59 @@ void TestTable::parseSQL()
QCOMPARE(tab.fields.at(0).type(), "integer");
QCOMPARE(tab.fields.at(1).type(), "text");
QCOMPARE(tab.fields.at(2).type(), QString("VARCHAR(255)"));
QCOMPARE(tab.fields.at(2).type(), "VARCHAR(255)");
QStringList pk = tab.primaryKey();
sqlb::StringVector pk = tab.primaryKey();
QVERIFY(tab.fields.at(0).autoIncrement());
QCOMPARE(pk.size(), 1);
QCOMPARE(pk.at(0), tab.fields.at(0).name());
QVERIFY(tab.fields.at(1).notnull());
QCOMPARE(tab.fields.at(1).defaultValue(), QString("'xxxx'"));
QCOMPARE(tab.fields.at(1).check(), QString(""));
QCOMPARE(tab.fields.at(2).check(), QString("info=='x'"));
QCOMPARE(tab.fields.at(1).defaultValue(), "'xxxx'");
QCOMPARE(tab.fields.at(1).check(), "");
QCOMPARE(tab.fields.at(2).check(), "info=='x'");
}
void TestTable::parseSQLdefaultexpr()
{
QString sSQL = "CREATE TABLE chtest(\n"
"id integer primary key,\n"
"dumpytext text default('axa') CHECK(dumpytext == \"aa\"),\n"
"date datetime default CURRENT_TIMESTAMP,"
"zoi integer)";
std::string sSQL = "CREATE TABLE chtest(\n"
"id integer primary key,\n"
"dumpytext text default('axa') CHECK(dumpytext == \"aa\"),\n"
"date datetime default CURRENT_TIMESTAMP,"
"zoi integer)";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
QCOMPARE(tab.name(), QString("chtest"));
QCOMPARE(tab.fields.at(0).name(), QString("id"));
QCOMPARE(tab.fields.at(1).name(), QString("dumpytext"));
QCOMPARE(tab.fields.at(2).name(), QString("date"));
QCOMPARE(tab.fields.at(3).name(), QString("zoi"));
QCOMPARE(tab.name(), "chtest");
QCOMPARE(tab.fields.at(0).name(), "id");
QCOMPARE(tab.fields.at(1).name(), "dumpytext");
QCOMPARE(tab.fields.at(2).name(), "date");
QCOMPARE(tab.fields.at(3).name(), "zoi");
QCOMPARE(tab.fields.at(0).type(), QString("integer"));
QCOMPARE(tab.fields.at(1).type(), QString("text"));
QCOMPARE(tab.fields.at(2).type(), QString("datetime"));
QCOMPARE(tab.fields.at(3).type(), QString("integer"));
QCOMPARE(tab.fields.at(0).type(), "integer");
QCOMPARE(tab.fields.at(1).type(), "text");
QCOMPARE(tab.fields.at(2).type(), "datetime");
QCOMPARE(tab.fields.at(3).type(), "integer");
QCOMPARE(tab.fields.at(1).defaultValue(), QString("('axa')"));
QCOMPARE(tab.fields.at(1).check(), QString("dumpytext==\"aa\""));
QCOMPARE(tab.fields.at(2).defaultValue(), QString("CURRENT_TIMESTAMP"));
QCOMPARE(tab.fields.at(2).check(), QString(""));
QCOMPARE(tab.fields.at(3).defaultValue(), QString(""));
QCOMPARE(tab.fields.at(3).check(), QString(""));
QCOMPARE(tab.fields.at(1).defaultValue(), "('axa')");
QCOMPARE(tab.fields.at(1).check(), "dumpytext==\"aa\"");
QCOMPARE(tab.fields.at(2).defaultValue(), "CURRENT_TIMESTAMP");
QCOMPARE(tab.fields.at(2).check(), "");
QCOMPARE(tab.fields.at(3).defaultValue(), "");
QCOMPARE(tab.fields.at(3).check(), "");
QStringList pk = tab.primaryKey();
sqlb::StringVector pk = tab.primaryKey();
QCOMPARE(pk.size(), 1);
QCOMPARE(pk.at(0), tab.fields.at(0).name());
}
void TestTable::parseSQLMultiPk()
{
QString sSQL = "CREATE TABLE hero (\n"
"\tid1 integer,\n"
"\tid2 integer,\n"
"\tnonpkfield blob,\n"
"PRIMARY KEY(\"id1\",\"id2\")\n"
");";
std::string sSQL = "CREATE TABLE hero (\n"
"\tid1 integer,\n"
"\tid2 integer,\n"
"\tnonpkfield blob,\n"
"PRIMARY KEY(\"id1\",\"id2\")\n"
");";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
@@ -247,7 +247,7 @@ void TestTable::parseSQLMultiPk()
QCOMPARE(tab.fields.at(0).type(), "integer");
QCOMPARE(tab.fields.at(1).type(), "integer");
QStringList pk = tab.primaryKey();
sqlb::StringVector pk = tab.primaryKey();
QCOMPARE(pk.size(), 2);
QCOMPARE(pk.at(0), tab.fields.at(0).name());
QCOMPARE(pk.at(1), tab.fields.at(1).name());
@@ -255,7 +255,7 @@ void TestTable::parseSQLMultiPk()
void TestTable::parseSQLForeignKey()
{
QString sSQL = "CREATE TABLE grammar_test(id, test, FOREIGN KEY(test) REFERENCES other_table);";
std::string sSQL = "CREATE TABLE grammar_test(id, test, FOREIGN KEY(test) REFERENCES other_table);";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
@@ -266,7 +266,7 @@ void TestTable::parseSQLForeignKey()
void TestTable::parseSQLSingleQuotes()
{
QString sSQL = "CREATE TABLE 'test'('id','test');";
std::string sSQL = "CREATE TABLE 'test'('id','test');";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
@@ -277,7 +277,7 @@ void TestTable::parseSQLSingleQuotes()
void TestTable::parseSQLSquareBrackets()
{
QString sSQL = "CREATE TABLE [test]([id],[test]);";
std::string sSQL = "CREATE TABLE [test]([id],[test]);";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
@@ -289,7 +289,7 @@ void TestTable::parseSQLSquareBrackets()
void TestTable::parseSQLKeywordInIdentifier()
{
QString sSQL = "CREATE TABLE deffered(key integer primary key, if text);";
std::string sSQL = "CREATE TABLE deffered(key integer primary key, if text);";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
@@ -301,9 +301,9 @@ void TestTable::parseSQLKeywordInIdentifier()
void TestTable::parseSQLSomeKeywordsInIdentifier()
{
QString sSQL = "CREATE TABLE \"Average Number of Volunteers by Area of Work\" ("
"`Area of Work` TEXT,"
"`Average Number of Volunteers` INTEGER);";
std::string sSQL = "CREATE TABLE \"Average Number of Volunteers by Area of Work\" ("
"`Area of Work` TEXT,"
"`Average Number of Volunteers` INTEGER);";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
@@ -314,7 +314,7 @@ void TestTable::parseSQLSomeKeywordsInIdentifier()
void TestTable::parseSQLWithoutRowid()
{
QString sSQL = "CREATE TABLE test(a integer primary key, b integer) WITHOUT ROWID;";
std::string sSQL = "CREATE TABLE test(a integer primary key, b integer) WITHOUT ROWID;";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
@@ -324,10 +324,10 @@ void TestTable::parseSQLWithoutRowid()
void TestTable::parseNonASCIIChars()
{
QString sSQL = "CREATE TABLE `lösung` ("
"`Fieldöäüß` INTEGER,"
"PRIMARY KEY(`Fieldöäüß`)"
");";
std::string sSQL = "CREATE TABLE `lösung` ("
"`Fieldöäüß` INTEGER,"
"PRIMARY KEY(`Fieldöäüß`)"
");";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
@@ -337,10 +337,10 @@ void TestTable::parseNonASCIIChars()
void TestTable::parseNonASCIICharsEs()
{
QString sSQL = "CREATE TABLE \"Cigüeñas de Alcalá\" ("
"\"Field áéíóúÁÉÍÓÚñÑçÇ\" INTEGER,"
"PRIMARY KEY(\"Field áéíóúÁÉÍÓÚñÑçÇ\")"
");";
std::string sSQL = "CREATE TABLE \"Cigüeñas de Alcalá\" ("
"\"Field áéíóúÁÉÍÓÚñÑçÇ\" INTEGER,"
"PRIMARY KEY(\"Field áéíóúÁÉÍÓÚñÑçÇ\")"
");";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
@@ -350,69 +350,69 @@ void TestTable::parseNonASCIICharsEs()
void TestTable::parseSQLEscapedQuotes()
{
QString sSql = "CREATE TABLE double_quotes(a text default 'a''a');";
std::string sSql = "CREATE TABLE double_quotes(a text default 'a''a');";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSql)));
QCOMPARE(tab.name(), QString("double_quotes"));
QCOMPARE(tab.fields.at(0).name(), QString("a"));
QCOMPARE(tab.fields.at(0).defaultValue(), QString("'a''a'"));
QCOMPARE(tab.name(), "double_quotes");
QCOMPARE(tab.fields.at(0).name(), "a");
QCOMPARE(tab.fields.at(0).defaultValue(), "'a''a'");
}
void TestTable::parseSQLForeignKeys()
{
QString sql = "CREATE TABLE foreign_key_test(a int, b int, foreign key (a) references x, foreign key (b) references w(y,z) on delete set null);";
std::string sql = "CREATE TABLE foreign_key_test(a int, b int, foreign key (a) references x, foreign key (b) references w(y,z) on delete set null);";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sql)));
QCOMPARE(tab.name(), QString("foreign_key_test"));
QCOMPARE(tab.fields.at(0).name(), QString("a"));
QCOMPARE(tab.fields.at(0).type(), QString("int"));
QCOMPARE(std::dynamic_pointer_cast<sqlb::ForeignKeyClause>(tab.constraint({tab.fields.at(0).name()}, sqlb::Constraint::ForeignKeyConstraintType))->table(), QString("x"));
QCOMPARE(tab.fields.at(1).name(), QString("b"));
QCOMPARE(tab.fields.at(1).type(), QString("int"));
QCOMPARE(std::dynamic_pointer_cast<sqlb::ForeignKeyClause>(tab.constraint({tab.fields.at(1).name()}, sqlb::Constraint::ForeignKeyConstraintType))->toString(), QString("\"w\"(\"y\",\"z\") on delete set null"));
QCOMPARE(tab.name(), "foreign_key_test");
QCOMPARE(tab.fields.at(0).name(), "a");
QCOMPARE(tab.fields.at(0).type(), "int");
QCOMPARE(std::dynamic_pointer_cast<sqlb::ForeignKeyClause>(tab.constraint({tab.fields.at(0).name()}, sqlb::Constraint::ForeignKeyConstraintType))->table(), "x");
QCOMPARE(tab.fields.at(1).name(), "b");
QCOMPARE(tab.fields.at(1).type(), "int");
QCOMPARE(std::dynamic_pointer_cast<sqlb::ForeignKeyClause>(tab.constraint({tab.fields.at(1).name()}, sqlb::Constraint::ForeignKeyConstraintType))->toString(), "\"w\"(\"y\",\"z\") on delete set null");
}
void TestTable::parseSQLCheckConstraint()
{
QString sql = "CREATE TABLE a (\"b\" text CHECK(\"b\"='A' or \"b\"='B'));";
std::string sql = "CREATE TABLE a (\"b\" text CHECK(\"b\"='A' or \"b\"='B'));";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sql)));
QCOMPARE(tab.name(), QString("a"));
QCOMPARE(tab.fields.at(0).name(), QString("b"));
QCOMPARE(tab.fields.at(0).type(), QString("text"));
QCOMPARE(tab.fields.at(0).check(), QString("\"b\"='A' or \"b\"='B'"));
QCOMPARE(tab.name(), "a");
QCOMPARE(tab.fields.at(0).name(), "b");
QCOMPARE(tab.fields.at(0).type(), "text");
QCOMPARE(tab.fields.at(0).check(), "\"b\"='A' or \"b\"='B'");
}
void TestTable::parseDefaultValues()
{
QString sql = "CREATE TABLE test(a int DEFAULT 0, b int DEFAULT -1, c text DEFAULT 'hello', d text DEFAULT '0');";
std::string sql = "CREATE TABLE test(a int DEFAULT 0, b int DEFAULT -1, c text DEFAULT 'hello', d text DEFAULT '0');";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sql)));
QCOMPARE(tab.name(), QString("test"));
QCOMPARE(tab.fields.at(0).name(), QString("a"));
QCOMPARE(tab.fields.at(0).type(), QString("int"));
QCOMPARE(tab.fields.at(0).defaultValue(), QString("0"));
QCOMPARE(tab.fields.at(1).name(), QString("b"));
QCOMPARE(tab.fields.at(1).type(), QString("int"));
QCOMPARE(tab.fields.at(1).defaultValue(), QString("-1"));
QCOMPARE(tab.fields.at(2).name(), QString("c"));
QCOMPARE(tab.fields.at(2).type(), QString("text"));
QCOMPARE(tab.fields.at(2).defaultValue(), QString("'hello'"));
QCOMPARE(tab.fields.at(3).name(), QString("d"));
QCOMPARE(tab.fields.at(3).type(), QString("text"));
QCOMPARE(tab.fields.at(3).defaultValue(), QString("'0'"));
QCOMPARE(tab.name(), "test");
QCOMPARE(tab.fields.at(0).name(), "a");
QCOMPARE(tab.fields.at(0).type(), "int");
QCOMPARE(tab.fields.at(0).defaultValue(), "0");
QCOMPARE(tab.fields.at(1).name(), "b");
QCOMPARE(tab.fields.at(1).type(), "int");
QCOMPARE(tab.fields.at(1).defaultValue(), "-1");
QCOMPARE(tab.fields.at(2).name(), "c");
QCOMPARE(tab.fields.at(2).type(), "text");
QCOMPARE(tab.fields.at(2).defaultValue(), "'hello'");
QCOMPARE(tab.fields.at(3).name(), "d");
QCOMPARE(tab.fields.at(3).type(), "text");
QCOMPARE(tab.fields.at(3).defaultValue(), "'0'");
}
void TestTable::createTableWithIn()
{
QString sSQL = "CREATE TABLE not_working("
"_id PRIMARY KEY NOT NULL,"
"value NVARCHAR(5) CHECK (value IN ('a', 'b', 'c'))"
");";
std::string sSQL = "CREATE TABLE not_working("
"_id PRIMARY KEY NOT NULL,"
"value NVARCHAR(5) CHECK (value IN ('a', 'b', 'c'))"
");";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
QCOMPARE(tab.name(), "not_working");
@@ -422,14 +422,14 @@ void TestTable::createTableWithIn()
void TestTable::createTableWithNotLikeConstraint()
{
QString sSQL = "CREATE TABLE hopefully_working(\n"
"value TEXT CONSTRAINT 'value' CHECK(value NOT LIKE 'prefix%'),\n"
"value2 TEXT CONSTRAINT 'value' CHECK(value2 NOT MATCH 'prefix%'),\n"
"value3 TEXT CONSTRAINT 'value' CHECK(value3 NOT REGEXP 'prefix%'),\n"
"value4 TEXT CONSTRAINT 'value' CHECK(value4 NOT GLOB 'prefix%'),\n"
"value5 INTEGER CONSTRAINT 'value' CHECK(value5 BETWEEN 1+4 AND 100 OR 200),\n"
"value6 INTEGER CONSTRAINT 'value' CHECK(value6 NOT BETWEEN 1 AND 100)\n"
");";
std::string sSQL = "CREATE TABLE hopefully_working(\n"
"value TEXT CHECK(value NOT LIKE 'prefix%'),\n"
"value2 TEXT CHECK(value2 NOT MATCH 'prefix%'),\n"
"value3 TEXT CHECK(value3 NOT REGEXP 'prefix%'),\n"
"value4 TEXT CHECK(value4 NOT GLOB 'prefix%'),\n"
"value5 INTEGER CHECK(value5 BETWEEN 1+4 AND 100 OR 200),\n"
"value6 INTEGER CHECK(value6 NOT BETWEEN 1 AND 100)\n"
");";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sSQL)));
QCOMPARE(tab.name(), "hopefully_working");
@@ -444,26 +444,26 @@ void TestTable::createTableWithNotLikeConstraint()
void TestTable::rowValues()
{
QString sql = "CREATE TABLE test(\n"
"a INTEGER,\n"
"b INTEGER,\n"
"CHECK((a, b) = (1, 2))\n"
");";
std::string sql = "CREATE TABLE test(\n"
"a INTEGER,\n"
"b INTEGER,\n"
"CHECK((a, b) = (1, 2))\n"
");";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sql)));
QCOMPARE(tab.name(), "test");
QCOMPARE(std::dynamic_pointer_cast<sqlb::CheckConstraint>(tab.constraint({}, sqlb::Constraint::CheckConstraintType))->expression(), QString("(a,b)=(1,2)"));
QCOMPARE(std::dynamic_pointer_cast<sqlb::CheckConstraint>(tab.constraint({}, sqlb::Constraint::CheckConstraintType))->expression(), "(a,b)=(1,2)");
}
void TestTable::complexExpressions()
{
QString sql = "CREATE TABLE test(\n"
"a INTEGER CHECK((a > 0)),\n"
"b INTEGER CHECK((b > 0 and b > 1)),\n"
"c INTEGER CHECK((c = -1) or (c > 0 and c > 1) or (c = 0)),\n"
"d INTEGER CHECK((((d > 0))))\n"
");";
std::string sql = "CREATE TABLE test(\n"
"a INTEGER CHECK((a > 0)),\n"
"b INTEGER CHECK((b > 0 and b > 1)),\n"
"c INTEGER CHECK((c = -1) or (c > 0 and c > 1) or (c = 0)),\n"
"d INTEGER CHECK((((d > 0))))\n"
");";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sql)));
QCOMPARE(tab.name(), "test");
@@ -476,9 +476,9 @@ void TestTable::complexExpressions()
void TestTable::datetimeExpression()
{
QString sql = "CREATE TABLE test(\n"
"entry INTEGER DEFAULT (DATETIME(CURRENT_TIMESTAMP, 'LOCALTIME'))\n"
");";
std::string sql = "CREATE TABLE test(\n"
"entry INTEGER DEFAULT (DATETIME(CURRENT_TIMESTAMP, 'LOCALTIME'))\n"
");";
Table tab = *(std::dynamic_pointer_cast<sqlb::Table>(Table::parseSQL(sql)));
QCOMPARE(tab.name(), "test");