mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-05-17 17:58:23 -05:00
Use some more SQL containers instead of their Qt equivalents
This commit is contained in:
+11
-12
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "sql/sqlitetypes.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QMap>
|
||||
|
||||
class DBBrowserDB;
|
||||
class QTreeWidgetItem;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <QDialog>
|
||||
#include <QVariant>
|
||||
#include <QHash>
|
||||
|
||||
class QTreeWidgetItem;
|
||||
class QFrame;
|
||||
|
||||
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user