mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-20 02:50:46 -06:00
Code refactoring
This changes the class structure in the sqlb namespace as well as the DBBrowserObject class. The rest of the commit are changes that are required by the modifications in sqlb and DBBrowserObject. The idea behind this refactoring is this: we currently have the DBBrowserObject class which holds some basic information about the database object (name, type, SQL string, etc.). It also contains a sqlb::Table and a sqlb::Index object. Those are used if the type of the object is table or index and they contain a whole lot more information on the object than the DBBrowserObject class, including the name, the type, the SQL string, etc. So we have a duplication here. There are two class structures for storing the same information. This has historic reasons but other than that there is no point in keeping it this way. With this commit I start the work of consolidating the sqlb classes in order to get rid of the DBBrowserObject class entirely. This commit only starts this task, it doesn't finish it. This is why it is a little messy here and there, but then again the old structure was a little messy, too. We will need at least a very basic trigger and view parser before finishing this is even possible. When this is done, I hope the ode will be much easier to read and understand. But even in the current state there already is some progress: we save a little bit of memory, don't copy big objects all the time anymore, and replace a lot of unnecessary string comparisons with integer comparisons.
This commit is contained in:
@@ -178,24 +178,32 @@ void DbStructureModel::reloadData()
|
||||
for(auto it=dbobjs.constBegin();it!=dbobjs.constEnd();++it)
|
||||
{
|
||||
// Object node
|
||||
QTreeWidgetItem* item = addNode(typeToParentItem.value((*it).gettype()), *it);
|
||||
QString type;
|
||||
switch((*it).gettype())
|
||||
{
|
||||
case sqlb::Object::ObjectTypes::Table: type = "table"; break;
|
||||
case sqlb::Object::ObjectTypes::Index: type = "index"; break;
|
||||
case sqlb::Object::ObjectTypes::Trigger: type = "trigger"; break;
|
||||
case sqlb::Object::ObjectTypes::View: type = "view"; break;
|
||||
}
|
||||
QTreeWidgetItem* item = addNode(typeToParentItem.value(type), *it);
|
||||
|
||||
// If it is a table or view add the field nodes
|
||||
if((*it).gettype() == "table" || (*it).gettype() == "view")
|
||||
if((*it).gettype() == sqlb::Object::ObjectTypes::Table || (*it).gettype() == sqlb::Object::ObjectTypes::View)
|
||||
{
|
||||
// Add extra node for browsable section
|
||||
addNode(typeToParentItem.value("browsable"), *it);
|
||||
|
||||
// Add field nodes
|
||||
sqlb::FieldVector pk = (*it).table.primaryKey();
|
||||
for(int i=0; i < (*it).table.fields().size(); ++i)
|
||||
sqlb::FieldVector pk = (*it).object.dynamicCast<sqlb::Table>()->primaryKey();
|
||||
for(int i=0; i < (*it).object.dynamicCast<sqlb::Table>()->fields().size(); ++i)
|
||||
{
|
||||
QTreeWidgetItem *fldItem = new QTreeWidgetItem(item);
|
||||
fldItem->setText(0, (*it).table.fields().at(i)->name());
|
||||
fldItem->setText(0, (*it).object.dynamicCast<sqlb::Table>()->fields().at(i)->name());
|
||||
fldItem->setText(1, "field");
|
||||
fldItem->setText(2, (*it).table.fields().at(i)->type());
|
||||
fldItem->setText(3, (*it).table.fields().at(i)->toString(" ", " "));
|
||||
if(pk.contains((*it).table.fields().at(i)))
|
||||
fldItem->setText(2, (*it).object.dynamicCast<sqlb::Table>()->fields().at(i)->type());
|
||||
fldItem->setText(3, (*it).object.dynamicCast<sqlb::Table>()->fields().at(i)->toString(" ", " "));
|
||||
if(pk.contains((*it).object.dynamicCast<sqlb::Table>()->fields().at(i)))
|
||||
fldItem->setIcon(0, QIcon(":/icons/field_key"));
|
||||
else
|
||||
fldItem->setIcon(0, QIcon(":/icons/field"));
|
||||
@@ -279,10 +287,19 @@ bool DbStructureModel::dropMimeData(const QMimeData* data, Qt::DropAction action
|
||||
|
||||
QTreeWidgetItem* DbStructureModel::addNode(QTreeWidgetItem* parent, const DBBrowserObject& object)
|
||||
{
|
||||
QString type;
|
||||
switch(object.gettype())
|
||||
{
|
||||
case sqlb::Object::ObjectTypes::Table: type = "table"; break;
|
||||
case sqlb::Object::ObjectTypes::Index: type = "index"; break;
|
||||
case sqlb::Object::ObjectTypes::Trigger: type = "trigger"; break;
|
||||
case sqlb::Object::ObjectTypes::View: type = "view"; break;
|
||||
}
|
||||
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(parent);
|
||||
item->setIcon(0, QIcon(QString(":/icons/%1").arg(object.gettype())));
|
||||
item->setIcon(0, QIcon(QString(":/icons/%1").arg(type)));
|
||||
item->setText(0, object.getname());
|
||||
item->setText(1, object.gettype());
|
||||
item->setText(1, type);
|
||||
item->setText(3, object.getsql());
|
||||
|
||||
return item;
|
||||
|
||||
@@ -33,7 +33,7 @@ EditIndexDialog::EditIndexDialog(DBBrowserDB& db, const QString& indexName, bool
|
||||
if(!newIndex)
|
||||
{
|
||||
// Load the current layour and fill in the dialog fields
|
||||
index = pdb.getObjectByName(curIndex).index;
|
||||
index = *(pdb.getObjectByName(curIndex).dynamicCast<sqlb::Index>());
|
||||
|
||||
ui->editIndexName->blockSignals(true);
|
||||
ui->editIndexName->setText(index.name());
|
||||
@@ -69,7 +69,7 @@ void EditIndexDialog::tableChanged(const QString& new_table, bool initialLoad)
|
||||
}
|
||||
|
||||
// And fill the table again
|
||||
QStringList fields = pdb.getObjectByName(new_table).table.fieldNames();
|
||||
QStringList fields = pdb.getObjectByName(new_table).dynamicCast<sqlb::Table>()->fieldNames();
|
||||
ui->tableIndexColumns->setRowCount(fields.size());
|
||||
for(int i=0; i < fields.size(); ++i)
|
||||
{
|
||||
|
||||
@@ -33,11 +33,11 @@ EditTableDialog::EditTableDialog(DBBrowserDB& db, const QString& tableName, bool
|
||||
if(m_bNewTable == false)
|
||||
{
|
||||
// Existing table, so load and set the current layout
|
||||
DBBrowserObject obj = pdb.getObjectByName(curTable);
|
||||
QString sTablesql = obj.getsql();
|
||||
QPair<sqlb::Table, bool> parse_result = sqlb::Table::parseSQL(sTablesql);
|
||||
m_table = parse_result.first;
|
||||
m_table.setTemporary(obj.isTemporary());
|
||||
sqlb::TablePtr obj = pdb.getObjectByName(curTable).dynamicCast<sqlb::Table>();
|
||||
QString sTablesql = obj->originalSql();
|
||||
QPair<sqlb::ObjectPtr, bool> parse_result = sqlb::Table::parseSQL(sTablesql);
|
||||
m_table = *(parse_result.first.dynamicCast<sqlb::Table>());
|
||||
m_table.setTemporary(obj->isTemporary());
|
||||
ui->labelEditWarning->setVisible(!parse_result.second);
|
||||
|
||||
// Set without rowid and temporary checkboxex. No need to trigger any events here as we're only loading a table exactly as it is stored by SQLite, so no need
|
||||
@@ -278,7 +278,7 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
|
||||
sqlb::FieldVector pk = m_table.primaryKey();
|
||||
foreach(const DBBrowserObject& fkobj, pdb.objMap.values("table"))
|
||||
{
|
||||
QList<sqlb::ConstraintPtr> fks = fkobj.table.constraints(sqlb::FieldVector(), sqlb::Constraint::ForeignKeyConstraintType);
|
||||
QList<sqlb::ConstraintPtr> fks = fkobj.object.dynamicCast<sqlb::Table>()->constraints(sqlb::FieldVector(), sqlb::Constraint::ForeignKeyConstraintType);
|
||||
foreach(sqlb::ConstraintPtr fkptr, fks)
|
||||
{
|
||||
QSharedPointer<sqlb::ForeignKeyClause> fk = fkptr.dynamicCast<sqlb::ForeignKeyClause>();
|
||||
@@ -350,7 +350,7 @@ 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 %3 IS NULL;")
|
||||
.arg(sqlb::escapeIdentifier(pdb.getObjectByName(curTable).table.rowidColumn()))
|
||||
.arg(sqlb::escapeIdentifier(pdb.getObjectByName(curTable).dynamicCast<sqlb::Table>()->rowidColumn()))
|
||||
.arg(sqlb::escapeIdentifier(curTable))
|
||||
.arg(sqlb::escapeIdentifier(field->name())));
|
||||
if(m.data(m.index(0, 0)).toInt() > 0)
|
||||
@@ -578,8 +578,7 @@ void EditTableDialog::removeField()
|
||||
QMessageBox::warning(0, QApplication::applicationName(), pdb.lastError());
|
||||
} else {
|
||||
//relayout
|
||||
QString sTablesql = pdb.getObjectByName(curTable).getsql();
|
||||
m_table = sqlb::Table::parseSQL(sTablesql).first;
|
||||
m_table = *(pdb.getObjectByName(curTable).dynamicCast<sqlb::Table>());
|
||||
populateFields();
|
||||
}
|
||||
}
|
||||
@@ -662,8 +661,7 @@ void EditTableDialog::moveCurrentField(bool down)
|
||||
QMessageBox::warning(0, QApplication::applicationName(), pdb.lastError());
|
||||
} else {
|
||||
// Reload table SQL
|
||||
QString sTablesql = pdb.getObjectByName(curTable).getsql();
|
||||
m_table = sqlb::Table::parseSQL(sTablesql).first;
|
||||
m_table = *(pdb.getObjectByName(curTable).dynamicCast<sqlb::Table>());
|
||||
populateFields();
|
||||
|
||||
// Select old item at new position
|
||||
|
||||
@@ -81,9 +81,9 @@ ForeignKeyEditorDelegate::ForeignKeyEditorDelegate(const DBBrowserDB& db, sqlb::
|
||||
{
|
||||
const auto objects = m_db.getBrowsableObjects();
|
||||
for (auto& obj : objects) {
|
||||
if ("table" == obj.gettype()) {
|
||||
QString tableName = obj.table.name();
|
||||
m_tablesIds.insert(tableName, obj.table.fieldNames());
|
||||
if (obj.gettype() == sqlb::Object::ObjectTypes::Table) {
|
||||
QString tableName = obj.object->name();
|
||||
m_tablesIds.insert(tableName, obj.object.dynamicCast<sqlb::Table>()->fieldNames());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,9 +186,9 @@ void ImportCsvDialog::accept()
|
||||
objectMap objects = pdb->getBrowsableObjects();
|
||||
for(auto it=objects.constBegin();it!=objects.constEnd();++it)
|
||||
{
|
||||
if(it.value().gettype() == "table" && it.value().getname() == ui->editName->text())
|
||||
if(it.value().gettype() == sqlb::Object::ObjectTypes::Table && it.value().getname() == ui->editName->text())
|
||||
{
|
||||
if((size_t)it.value().table.fields().size() != csv.columns())
|
||||
if((size_t)it.value().object.dynamicCast<sqlb::Table>()->fields().size() != csv.columns())
|
||||
{
|
||||
QMessageBox::warning(this, QApplication::applicationName(),
|
||||
tr("There is already a table of that name and an import into an existing table is only possible if the number of columns match."));
|
||||
|
||||
@@ -366,9 +366,9 @@ void MainWindow::populateStructure()
|
||||
{
|
||||
QString objectname = it.value().getname();
|
||||
|
||||
for(int i=0; i < (*it).table.fields().size(); ++i)
|
||||
for(int i=0; i < (*it).object.dynamicCast<sqlb::Table>()->fields().size(); ++i)
|
||||
{
|
||||
QString fieldname = (*it).table.fields().at(i)->name();
|
||||
QString fieldname = (*it).object.dynamicCast<sqlb::Table>()->fields().at(i)->name();
|
||||
tablesToColumnsMap[objectname].append(fieldname);
|
||||
}
|
||||
}
|
||||
@@ -429,7 +429,7 @@ void MainWindow::populateTable()
|
||||
} else {
|
||||
QVector<QString> v;
|
||||
bool only_defaults = true;
|
||||
const sqlb::FieldVector& tablefields = db.getObjectByName(tablename).table.fields();
|
||||
const sqlb::FieldVector& tablefields = db.getObjectByName(tablename).dynamicCast<sqlb::Table>()->fields();
|
||||
for(int i=0; i<tablefields.size(); ++i)
|
||||
{
|
||||
QString format = tableIt.value().displayFormats[i+1];
|
||||
@@ -498,7 +498,7 @@ void MainWindow::populateTable()
|
||||
}
|
||||
|
||||
// Activate the add and delete record buttons and editing only if a table has been selected
|
||||
bool editable = db.getObjectByName(tablename).gettype() == "table" && !db.readOnly();
|
||||
bool editable = db.getObjectByName(tablename)->type() == sqlb::Object::ObjectTypes::Table && !db.readOnly();
|
||||
ui->buttonNewRecord->setEnabled(editable);
|
||||
ui->buttonDeleteRecord->setEnabled(editable);
|
||||
ui->dataTable->setEditTriggers(editable ? QAbstractItemView::SelectedClicked | QAbstractItemView::AnyKeyPressed | QAbstractItemView::EditKeyPressed : QAbstractItemView::NoEditTriggers);
|
||||
@@ -816,7 +816,7 @@ void MainWindow::doubleClickTable(const QModelIndex& index)
|
||||
|
||||
// * Don't allow editing of other objects than tables (on the browse table) *
|
||||
bool isEditingAllowed = (m_currentTabTableModel == m_browseTableModel) &&
|
||||
(db.getObjectByName(ui->comboBrowseTable->currentText()).gettype() == "table");
|
||||
(db.getObjectByName(ui->comboBrowseTable->currentText())->type() == sqlb::Object::ObjectTypes::Table);
|
||||
|
||||
// Enable or disable the Apply, Null, & Import buttons in the Edit Cell
|
||||
// dock depending on the value of the "isEditingAllowed" bool above
|
||||
@@ -840,7 +840,7 @@ void MainWindow::dataTableSelectionChanged(const QModelIndex& index)
|
||||
}
|
||||
|
||||
bool editingAllowed = (m_currentTabTableModel == m_browseTableModel) &&
|
||||
(db.getObjectByName(ui->comboBrowseTable->currentText()).gettype() == "table");
|
||||
(db.getObjectByName(ui->comboBrowseTable->currentText())->type() == sqlb::Object::ObjectTypes::Table);
|
||||
|
||||
// Don't allow editing of other objects than tables
|
||||
editDock->setReadOnly(!editingAllowed);
|
||||
@@ -2195,16 +2195,16 @@ void MainWindow::copyCurrentCreateStatement()
|
||||
void MainWindow::jumpToRow(const QString& table, QString column, const QByteArray& value)
|
||||
{
|
||||
// First check if table exists
|
||||
DBBrowserObject obj = db.getObjectByName(table);
|
||||
if(obj.getname().size() == 0)
|
||||
sqlb::TablePtr obj = db.getObjectByName(table).dynamicCast<sqlb::Table>();
|
||||
if(!obj)
|
||||
return;
|
||||
|
||||
// If no column name is set, assume the primary key is meant
|
||||
if(!column.size())
|
||||
column = obj.table.fields().at(obj.table.findPk())->name();
|
||||
column = obj->fields().at(obj->findPk())->name();
|
||||
|
||||
// If column doesn't exist don't do anything
|
||||
int column_index = obj.table.findField(column);
|
||||
int column_index = obj->findField(column);
|
||||
if(column_index == -1)
|
||||
return;
|
||||
|
||||
@@ -2232,7 +2232,7 @@ void MainWindow::showDataColumnPopupMenu(const QPoint& pos)
|
||||
void MainWindow::showRecordPopupMenu(const QPoint& pos)
|
||||
{
|
||||
const QString sCurrentTable = ui->comboBrowseTable->currentText();
|
||||
if (!(db.getObjectByName(sCurrentTable).gettype() == "table" && !db.readOnly()))
|
||||
if(!(db.getObjectByName(sCurrentTable)->type() == sqlb::Object::ObjectTypes::Table && !db.readOnly()))
|
||||
return;
|
||||
|
||||
int row = ui->dataTable->verticalHeader()->logicalIndexAt(pos);
|
||||
@@ -2257,7 +2257,7 @@ void MainWindow::editDataColumnDisplayFormat()
|
||||
// column is always the rowid column. Ultimately, get the column name from the column object
|
||||
QString current_table = ui->comboBrowseTable->currentText();
|
||||
int field_number = sender()->property("clicked_column").toInt();
|
||||
QString field_name = db.getObjectByName(current_table).table.fields().at(field_number-1)->name();
|
||||
QString field_name = db.getObjectByName(current_table).dynamicCast<sqlb::Table>()->fields().at(field_number-1)->name();
|
||||
|
||||
// Get the current display format of the field
|
||||
QString current_displayformat = browseTableSettings[current_table].displayFormats[field_number];
|
||||
|
||||
@@ -96,14 +96,12 @@ void SqlExecutionArea::saveAsView()
|
||||
{
|
||||
name = QInputDialog::getText(this, qApp->applicationName(), tr("Please specify the view name")).trimmed();
|
||||
if(name.isEmpty())
|
||||
break;
|
||||
if(!db.getObjectByName(name).getname().isEmpty())
|
||||
return;
|
||||
if(db.getObjectByName(name) != nullptr)
|
||||
QMessageBox::warning(this, qApp->applicationName(), tr("There is already an object with that name. Please choose a different name."));
|
||||
else
|
||||
break;
|
||||
}
|
||||
if(name.isEmpty())
|
||||
return;
|
||||
|
||||
// Create the view
|
||||
if(db.executeSQL(QString("CREATE VIEW %1 AS %2;").arg(sqlb::escapeIdentifier(name)).arg(model->query())))
|
||||
|
||||
@@ -503,7 +503,7 @@ bool DBBrowserDB::dump(const QString& filename,
|
||||
continue;
|
||||
|
||||
// get columns
|
||||
QStringList cols(it->table.fieldNames());
|
||||
QStringList cols(it->object.dynamicCast<sqlb::Table>()->fieldNames());
|
||||
|
||||
QString sQuery = QString("SELECT * FROM %1;").arg(sqlb::escapeIdentifier(it->getTableName()));
|
||||
QByteArray utf8Query = sQuery.toUtf8();
|
||||
@@ -522,7 +522,7 @@ bool DBBrowserDB::dump(const QString& filename,
|
||||
|
||||
if (!insertNewSyntx || !counter)
|
||||
{
|
||||
stream << "INSERT INTO " << sqlb::escapeIdentifier(it->getTableName());
|
||||
stream << "INSERT INTO " << sqlb::escapeIdentifier(it->getname());
|
||||
if (insertColNames)
|
||||
stream << " (" << cols.join(",") << ")";
|
||||
stream << " VALUES (";
|
||||
@@ -594,7 +594,7 @@ bool DBBrowserDB::dump(const QString& filename,
|
||||
for(auto it=objMap.constBegin();it!=objMap.constEnd();++it)
|
||||
{
|
||||
// Make sure it's not a table again
|
||||
if(it.value().gettype() == "table")
|
||||
if(it.value().gettype() == sqlb::Object::ObjectTypes::Table)
|
||||
continue;
|
||||
|
||||
// Write the SQL string used to create this object to the output file
|
||||
@@ -732,7 +732,7 @@ bool DBBrowserDB::getRow(const QString& sTableName, const QString& rowid, QList<
|
||||
{
|
||||
QString sQuery = QString("SELECT * FROM %1 WHERE %2='%3';")
|
||||
.arg(sqlb::escapeIdentifier(sTableName))
|
||||
.arg(sqlb::escapeIdentifier(getObjectByName(sTableName).table.rowidColumn()))
|
||||
.arg(sqlb::escapeIdentifier(getObjectByName(sTableName).dynamicCast<sqlb::Table>()->rowidColumn()))
|
||||
.arg(rowid);
|
||||
|
||||
QByteArray utf8Query = sQuery.toUtf8();
|
||||
@@ -853,18 +853,18 @@ QString DBBrowserDB::addRecord(const QString& sTableName)
|
||||
{
|
||||
if (!isOpen()) return QString();
|
||||
|
||||
sqlb::Table table = getObjectByName(sTableName).table;
|
||||
sqlb::TablePtr table = getObjectByName(sTableName).dynamicCast<sqlb::Table>();
|
||||
|
||||
// For tables without rowid we have to set the primary key by ourselves. We do so by querying for the largest value in the PK column
|
||||
// and adding one to it.
|
||||
QString sInsertstmt;
|
||||
QString pk_value;
|
||||
if(table.isWithoutRowidTable())
|
||||
if(table->isWithoutRowidTable())
|
||||
{
|
||||
pk_value = QString::number(max(table, table.fields().at(table.findField(table.rowidColumn()))).toLongLong() + 1);
|
||||
sInsertstmt = emptyInsertStmt(table, pk_value);
|
||||
pk_value = QString::number(max(*table, table->fields().at(table->findField(table->rowidColumn()))).toLongLong() + 1);
|
||||
sInsertstmt = emptyInsertStmt(*table, pk_value);
|
||||
} else {
|
||||
sInsertstmt = emptyInsertStmt(table);
|
||||
sInsertstmt = emptyInsertStmt(*table);
|
||||
}
|
||||
|
||||
if(!executeSQL(sInsertstmt))
|
||||
@@ -872,7 +872,7 @@ QString DBBrowserDB::addRecord(const QString& sTableName)
|
||||
qWarning() << "addRecord: " << lastErrorMessage;
|
||||
return QString();
|
||||
} else {
|
||||
if(table.isWithoutRowidTable())
|
||||
if(table->isWithoutRowidTable())
|
||||
return pk_value;
|
||||
else
|
||||
return QString::number(sqlite3_last_insert_rowid(_db));
|
||||
@@ -891,7 +891,7 @@ bool DBBrowserDB::deleteRecords(const QString& table, const QStringList& rowids)
|
||||
}
|
||||
QString statement = QString("DELETE FROM %1 WHERE %2 IN (%3);")
|
||||
.arg(sqlb::escapeIdentifier(table))
|
||||
.arg(sqlb::escapeIdentifier(getObjectByName(table).table.rowidColumn()))
|
||||
.arg(sqlb::escapeIdentifier(getObjectByName(table).dynamicCast<sqlb::Table>()->rowidColumn()))
|
||||
.arg(quoted_rowids.join(", "));
|
||||
if(executeSQL(statement))
|
||||
ok = true;
|
||||
@@ -908,7 +908,7 @@ bool DBBrowserDB::updateRecord(const QString& table, const QString& column, cons
|
||||
QString sql = QString("UPDATE %1 SET %2=? WHERE %3='%4';")
|
||||
.arg(sqlb::escapeIdentifier(table))
|
||||
.arg(sqlb::escapeIdentifier(column))
|
||||
.arg(sqlb::escapeIdentifier(getObjectByName(table).table.rowidColumn()))
|
||||
.arg(sqlb::escapeIdentifier(getObjectByName(table).dynamicCast<sqlb::Table>()->rowidColumn()))
|
||||
.arg(rowid);
|
||||
|
||||
logSQL(sql, kLogMsg_App);
|
||||
@@ -994,19 +994,11 @@ bool DBBrowserDB::renameColumn(const QString& tablename, const sqlb::Table& tabl
|
||||
// 2) Include the addColumn() use case in here, so the calling side doesn't need to know anything about how this class handles table modifications.
|
||||
// 3) Maybe rename this function to alterTable() or something
|
||||
|
||||
// Collect information on the current DB layout
|
||||
QString tableSql = getObjectByName(tablename).getsql();
|
||||
if(tableSql.isEmpty())
|
||||
{
|
||||
lastErrorMessage = tr("renameColumn: cannot find table %1.").arg(tablename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create table schema
|
||||
sqlb::Table oldSchema = sqlb::Table::parseSQL(tableSql).first;
|
||||
const sqlb::TablePtr oldSchema = getObjectByName(tablename).dynamicCast<sqlb::Table>();
|
||||
|
||||
// Check if field actually exists
|
||||
if(!name.isNull() && oldSchema.findField(name) == -1)
|
||||
if(!name.isNull() && oldSchema->findField(name) == -1)
|
||||
{
|
||||
lastErrorMessage = tr("renameColumn: cannot find column %1.").arg(name);
|
||||
return false;
|
||||
@@ -1022,7 +1014,7 @@ bool DBBrowserDB::renameColumn(const QString& tablename, const sqlb::Table& tabl
|
||||
// Create a new table with a name that hopefully doesn't exist yet.
|
||||
// Its layout is exactly the same as the one of the table to change - except for the column to change
|
||||
// of course, and the table constraints which are copied from the table parameter.
|
||||
sqlb::Table newSchema = oldSchema;
|
||||
sqlb::Table newSchema = *oldSchema;
|
||||
newSchema.setName("sqlitebrowser_rename_column_new_table");
|
||||
newSchema.setConstraints(table.allConstraints());
|
||||
newSchema.setRowidColumn(table.rowidColumn());
|
||||
@@ -1084,19 +1076,19 @@ bool DBBrowserDB::renameColumn(const QString& tablename, const sqlb::Table& tabl
|
||||
for(auto it=objMap.constBegin();it!=objMap.constEnd();++it)
|
||||
{
|
||||
// If this object references the table and it's not the table itself save it's SQL string
|
||||
if((*it).getTableName() == tablename && (*it).gettype() != "table")
|
||||
if((*it).getTableName() == tablename && (*it).gettype() != sqlb::Object::ObjectTypes::Table)
|
||||
{
|
||||
// If this is an index, update the fields first. This highly increases the chance that the SQL statement won't throw an
|
||||
// error later on when we try to recreate it.
|
||||
if((*it).gettype() == "index")
|
||||
if((*it).gettype() == sqlb::Object::ObjectTypes::Index)
|
||||
{
|
||||
sqlb::Index idx = (*it).index;
|
||||
for(int i=0;i<idx.columns().size();i++)
|
||||
sqlb::IndexPtr idx = (*it).object.dynamicCast<sqlb::Index>();
|
||||
for(int i=0;i<idx->columns().size();i++)
|
||||
{
|
||||
if(idx.column(i)->name() == name)
|
||||
idx.column(i)->setName(to->name());
|
||||
if(idx->column(i)->name() == name)
|
||||
idx->column(i)->setName(to->name());
|
||||
}
|
||||
otherObjectsSql << idx.sql();
|
||||
otherObjectsSql << idx->sql();
|
||||
} 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.
|
||||
@@ -1187,14 +1179,14 @@ objectMap DBBrowserDB::getBrowsableObjects() const
|
||||
return res;
|
||||
}
|
||||
|
||||
DBBrowserObject DBBrowserDB::getObjectByName(const QString& name) const
|
||||
sqlb::ObjectPtr DBBrowserDB::getObjectByName(const QString& name) const
|
||||
{
|
||||
for(auto it=objMap.constBegin();it!=objMap.constEnd();++it)
|
||||
{
|
||||
if((*it).getname() == name)
|
||||
return *it;
|
||||
return it->object;
|
||||
}
|
||||
return DBBrowserObject();
|
||||
return sqlb::ObjectPtr(nullptr);
|
||||
}
|
||||
|
||||
void DBBrowserDB::logSQL(QString statement, int msgtype)
|
||||
@@ -1237,6 +1229,7 @@ void DBBrowserDB::updateSchema( )
|
||||
QByteArray utf8Statement = statement.toUtf8();
|
||||
err=sqlite3_prepare_v2(_db, utf8Statement, utf8Statement.length(),
|
||||
&vm, &tail);
|
||||
QVector<QString> temporary_objects;
|
||||
if (err == SQLITE_OK){
|
||||
logSQL(statement, kLogMsg_App);
|
||||
while ( sqlite3_step(vm) == SQLITE_ROW ){
|
||||
@@ -1247,32 +1240,45 @@ void DBBrowserDB::updateSchema( )
|
||||
QString val_temp = QString::fromUtf8((const char*)sqlite3_column_text(vm, 4));
|
||||
val_sql.replace("\r", "");
|
||||
|
||||
if(val_type == "table" || val_type == "index" || val_type == "view" || val_type == "trigger")
|
||||
objMap.insert(val_type, DBBrowserObject(val_name, val_sql, val_type, val_tblname, (val_temp == "1")));
|
||||
sqlb::Object::ObjectTypes type;
|
||||
if(val_type == "table")
|
||||
type = sqlb::Object::ObjectTypes::Table;
|
||||
else if(val_type == "index")
|
||||
type = sqlb::Object::ObjectTypes::Index;
|
||||
else if(val_type == "trigger")
|
||||
type = sqlb::Object::ObjectTypes::Trigger;
|
||||
else if(val_type == "view")
|
||||
type = sqlb::Object::ObjectTypes::View;
|
||||
else
|
||||
qWarning() << tr("unknown object type %1").arg(val_type);
|
||||
continue;
|
||||
|
||||
DBBrowserObject obj(val_name, val_sql, type, val_tblname);
|
||||
if((type == sqlb::Object::ObjectTypes::Table || type == sqlb::Object::ObjectTypes::Index) && !val_sql.isEmpty())
|
||||
{
|
||||
obj.object = sqlb::Object::parseSQL(type, val_sql).first;
|
||||
if(val_temp == "1")
|
||||
obj.object->setTemporary(true);
|
||||
}
|
||||
objMap.insert(val_type, obj);
|
||||
}
|
||||
sqlite3_finalize(vm);
|
||||
}else{
|
||||
qWarning() << tr("could not get list of db objects: %1, %2").arg(err).arg(sqlite3_errmsg(_db));
|
||||
}
|
||||
|
||||
//now get the field list for each table
|
||||
//now get the field list for views
|
||||
objectMap::Iterator it;
|
||||
for ( it = objMap.begin(); it != objMap.end(); ++it )
|
||||
{
|
||||
// Use our SQL parser to generate the field list for tables. For views we currently have to fall back to the
|
||||
// pragma SQLite offers.
|
||||
if((*it).gettype() == "table")
|
||||
if((*it).gettype() == sqlb::Object::ObjectTypes::View)
|
||||
{
|
||||
(*it).table = sqlb::Table::parseSQL((*it).getsql()).first;
|
||||
} else if((*it).gettype() == "index" && !(*it).getsql().isEmpty()) {
|
||||
(*it).index = sqlb::Index::parseSQL((*it).getsql()).first;
|
||||
} else if((*it).gettype() == "view") {
|
||||
statement = QString("PRAGMA TABLE_INFO(%1);").arg(sqlb::escapeIdentifier((*it).getname()));
|
||||
logSQL(statement, kLogMsg_App);
|
||||
err=sqlite3_prepare_v2(_db,statement.toUtf8(),statement.length(),
|
||||
&vm, &tail);
|
||||
sqlb::Table* view_dummy = new sqlb::Table("");
|
||||
if (err == SQLITE_OK){
|
||||
while ( sqlite3_step(vm) == SQLITE_ROW ){
|
||||
if (sqlite3_column_count(vm)==6)
|
||||
@@ -1281,13 +1287,14 @@ void DBBrowserDB::updateSchema( )
|
||||
QString val_type = QString::fromUtf8((const char *)sqlite3_column_text(vm, 2));
|
||||
|
||||
sqlb::FieldPtr f(new sqlb::Field(val_name, val_type));
|
||||
(*it).table.addField(f);
|
||||
view_dummy->addField(f);
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(vm);
|
||||
} else{
|
||||
lastErrorMessage = tr("could not get types");
|
||||
}
|
||||
(*it).object = sqlb::TablePtr(view_dummy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,25 +21,22 @@ typedef QMultiMap<QString, class DBBrowserObject> objectMap;
|
||||
class DBBrowserObject
|
||||
{
|
||||
public:
|
||||
DBBrowserObject() : table(""), index(""), name( "" ) { }
|
||||
DBBrowserObject(const QString& wname, const QString& wsql, const QString& wtype, const QString& tbl_name, bool temp)
|
||||
: table(wname), index(wname), name( wname), sql( wsql ), type(wtype), table_name(tbl_name), temporary(temp)
|
||||
DBBrowserObject() : name( "" ) { }
|
||||
DBBrowserObject(const QString& wname, const QString& wsql, sqlb::Object::ObjectTypes wtype, const QString& tbl_name)
|
||||
: name( wname), sql( wsql ), type(wtype), table_name(tbl_name)
|
||||
{ }
|
||||
|
||||
QString getname() const { return name; }
|
||||
QString getsql() const { return sql; }
|
||||
QString gettype() const { return type; }
|
||||
sqlb::Object::ObjectTypes gettype() const { return type; }
|
||||
QString getTableName() const { return table_name; }
|
||||
bool isTemporary() const { return temporary; }
|
||||
|
||||
sqlb::Table table;
|
||||
sqlb::Index index;
|
||||
sqlb::ObjectPtr object;
|
||||
private:
|
||||
QString name;
|
||||
QString sql;
|
||||
QString type;
|
||||
sqlb::Object::ObjectTypes type;
|
||||
QString table_name; // The name of the table this object references, interesting for views, triggers and indices
|
||||
bool temporary;
|
||||
};
|
||||
|
||||
class DBBrowserDB : public QObject
|
||||
@@ -109,7 +106,7 @@ public:
|
||||
bool renameColumn(const QString& tablename, const sqlb::Table& table, const QString& name, sqlb::FieldPtr to, int move = 0);
|
||||
|
||||
objectMap getBrowsableObjects() const;
|
||||
DBBrowserObject getObjectByName(const QString& name) const;
|
||||
sqlb::ObjectPtr getObjectByName(const QString& name) const;
|
||||
bool isOpen() const;
|
||||
bool encrypted() const { return isEncrypted; }
|
||||
bool readOnly() const { return isReadOnly; }
|
||||
|
||||
@@ -47,13 +47,13 @@ void SqliteTableModel::setTable(const QString& table, const QVector<QString>& di
|
||||
m_vDataTypes.push_back(SQLITE_INTEGER);
|
||||
|
||||
bool allOk = false;
|
||||
if(m_db.getObjectByName(table).gettype() == "table")
|
||||
if(m_db.getObjectByName(table)->type() == sqlb::Object::ObjectTypes::Table)
|
||||
{
|
||||
sqlb::Table t = sqlb::Table::parseSQL(m_db.getObjectByName(table).getsql()).first;
|
||||
if(t.fields().size()) // parsing was OK
|
||||
sqlb::TablePtr t = sqlb::Table::parseSQL(m_db.getObjectByName(table)->originalSql()).first.dynamicCast<sqlb::Table>();
|
||||
if(t->fields().size()) // parsing was OK
|
||||
{
|
||||
m_headers.push_back(t.rowidColumn());
|
||||
m_headers.append(t.fieldNames());
|
||||
m_headers.push_back(t->rowidColumn());
|
||||
m_headers.append(t->fieldNames());
|
||||
|
||||
// parse columns types
|
||||
static QStringList dataTypes = QStringList()
|
||||
@@ -61,7 +61,7 @@ void SqliteTableModel::setTable(const QString& table, const QVector<QString>& di
|
||||
<< "REAL"
|
||||
<< "TEXT"
|
||||
<< "BLOB";
|
||||
foreach(const sqlb::FieldPtr fld, t.fields())
|
||||
foreach(const sqlb::FieldPtr fld, t->fields())
|
||||
{
|
||||
QString name(fld->type().toUpper());
|
||||
int colType = dataTypes.indexOf(name);
|
||||
@@ -267,13 +267,13 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
|
||||
|
||||
sqlb::ForeignKeyClause SqliteTableModel::getForeignKeyClause(int column) const
|
||||
{
|
||||
DBBrowserObject obj = m_db.getObjectByName(m_sTable);
|
||||
if(obj.getname().size() && (column >= 0 && column < obj.table.fields().count()))
|
||||
sqlb::TablePtr obj = m_db.getObjectByName(m_sTable).dynamicCast<sqlb::Table>();
|
||||
if(obj->name().size() && (column >= 0 && column < obj->fields().count()))
|
||||
{
|
||||
// Note that the rowid column has number -1 here, it can safely be excluded since there will never be a
|
||||
// foreign key on that column.
|
||||
|
||||
sqlb::ConstraintPtr ptr = obj.table.constraint({obj.table.fields().at(column)}, sqlb::Constraint::ForeignKeyConstraintType);
|
||||
sqlb::ConstraintPtr ptr = obj->constraint({obj->fields().at(column)}, sqlb::Constraint::ForeignKeyConstraintType);
|
||||
if(ptr)
|
||||
return *(ptr.dynamicCast<sqlb::ForeignKeyClause>());
|
||||
}
|
||||
@@ -432,11 +432,11 @@ QModelIndex SqliteTableModel::dittoRecord(int old_row)
|
||||
int firstEditedColumn = 0;
|
||||
int new_row = rowCount() - 1;
|
||||
|
||||
sqlb::Table t = sqlb::Table::parseSQL(m_db.getObjectByName(m_sTable).getsql()).first;
|
||||
sqlb::TablePtr t = sqlb::Table::parseSQL(m_db.getObjectByName(m_sTable)->originalSql()).first.dynamicCast<sqlb::Table>();
|
||||
|
||||
sqlb::FieldVector pk = t.primaryKey();
|
||||
for (int col = 0; col < t.fields().size(); ++col) {
|
||||
if(!pk.contains(t.fields().at(col))) {
|
||||
sqlb::FieldVector pk = t->primaryKey();
|
||||
for (int col = 0; col < t->fields().size(); ++col) {
|
||||
if(!pk.contains(t->fields().at(col))) {
|
||||
if (!firstEditedColumn)
|
||||
firstEditedColumn = col + 1;
|
||||
|
||||
|
||||
@@ -22,6 +22,27 @@ QStringList fieldVectorToFieldNames(const FieldVector& vector)
|
||||
return result;
|
||||
}
|
||||
|
||||
QPair<ObjectPtr, bool> Object::parseSQL(Object::ObjectTypes type, const QString& sSQL)
|
||||
{
|
||||
// Parse SQL statement according to type
|
||||
QPair<ObjectPtr, bool> result;
|
||||
switch(type)
|
||||
{
|
||||
case Object::ObjectTypes::Table:
|
||||
result = Table::parseSQL(sSQL);
|
||||
break;
|
||||
case Object::ObjectTypes::Index:
|
||||
result = Index::parseSQL(sSQL);
|
||||
break;
|
||||
default:
|
||||
return QPair<ObjectPtr, bool>(ObjectPtr(nullptr), false);
|
||||
}
|
||||
|
||||
// Strore the original SQL statement and return the result
|
||||
result.first->setOriginalSql(sSQL);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ForeignKeyClause::isSet() const
|
||||
{
|
||||
return m_override.size() || m_table.size();
|
||||
@@ -256,7 +277,7 @@ bool Table::hasAutoIncrement() const
|
||||
return false;
|
||||
}
|
||||
|
||||
QPair<Table, bool> Table::parseSQL(const QString &sSQL)
|
||||
QPair<ObjectPtr, bool> Table::parseSQL(const QString &sSQL)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << sSQL.toStdString();
|
||||
@@ -276,7 +297,7 @@ QPair<Table, bool> Table::parseSQL(const QString &sSQL)
|
||||
// Note: this needs to be done in two separate lines because otherwise the optimiser might decide to
|
||||
// fetch the value for the second part of the pair (the modify supported flag) first. If it does so it will
|
||||
// always be set to true because the table() method hasn't run yet and it's only set to false in there.
|
||||
sqlb::Table tab = ctw.table();
|
||||
sqlb::TablePtr tab = ctw.table();
|
||||
return qMakePair(tab, ctw.modifysupported());
|
||||
}
|
||||
catch(antlr::ANTLRException& ex)
|
||||
@@ -288,7 +309,7 @@ QPair<Table, bool> Table::parseSQL(const QString &sSQL)
|
||||
qCritical() << "Sqlite parse error: " << sSQL; //TODO
|
||||
}
|
||||
|
||||
return qMakePair(Table(""), false);
|
||||
return qMakePair(TablePtr(new Table("")), false);
|
||||
}
|
||||
|
||||
QString Table::sql() const
|
||||
@@ -463,9 +484,9 @@ QString columnname(const antlr::RefAST& n)
|
||||
}
|
||||
}
|
||||
|
||||
Table CreateTableWalker::table()
|
||||
TablePtr CreateTableWalker::table()
|
||||
{
|
||||
Table tab("");
|
||||
Table* tab = new Table("");
|
||||
|
||||
if( m_root ) //CREATE TABLE
|
||||
{
|
||||
@@ -491,7 +512,7 @@ Table CreateTableWalker::table()
|
||||
}
|
||||
|
||||
// Extract and set table name
|
||||
tab.setName(tablename(s));
|
||||
tab->setName(tablename(s));
|
||||
|
||||
// Special handling for virtual tables. If this is a virtual table, extract the USING part and skip all the
|
||||
// rest of this function because virtual tables don't have column definitons
|
||||
@@ -499,12 +520,12 @@ Table CreateTableWalker::table()
|
||||
{
|
||||
s = s->getNextSibling(); // USING
|
||||
s = s->getNextSibling(); // module name
|
||||
tab.setVirtualUsing(concatTextAST(s, true));
|
||||
tab->setVirtualUsing(concatTextAST(s, true));
|
||||
m_bModifySupported = false;
|
||||
|
||||
// TODO Maybe get the column list using the 'pragma table_info()' approach we're using for views
|
||||
|
||||
return tab;
|
||||
return TablePtr(tab);
|
||||
}
|
||||
|
||||
// This is a normal table, not a virtual one
|
||||
@@ -555,7 +576,7 @@ Table CreateTableWalker::table()
|
||||
do
|
||||
{
|
||||
QString col = columnname(tc);
|
||||
FieldPtr field = tab.field(tab.findField(col));
|
||||
FieldPtr field = tab->field(tab->findField(col));
|
||||
fields.push_back(field);
|
||||
|
||||
tc = tc->getNextSibling();
|
||||
@@ -579,7 +600,7 @@ Table CreateTableWalker::table()
|
||||
}
|
||||
} while(tc != antlr::nullAST && tc->getType() != sqlite3TokenTypes::RPAREN);
|
||||
|
||||
tab.addConstraint(fields, ConstraintPtr(pk));
|
||||
tab->addConstraint(fields, ConstraintPtr(pk));
|
||||
}
|
||||
break;
|
||||
case sqlite3TokenTypes::UNIQUE:
|
||||
@@ -593,7 +614,7 @@ Table CreateTableWalker::table()
|
||||
do
|
||||
{
|
||||
QString col = columnname(tc);
|
||||
FieldPtr field = tab.field(tab.findField(col));
|
||||
FieldPtr field = tab->field(tab->findField(col));
|
||||
fields.push_back(field);
|
||||
|
||||
tc = tc->getNextSibling();
|
||||
@@ -617,7 +638,7 @@ Table CreateTableWalker::table()
|
||||
fields[0]->setUnique(true);
|
||||
delete unique;
|
||||
} else {
|
||||
tab.addConstraint(fields, ConstraintPtr(unique));
|
||||
tab->addConstraint(fields, ConstraintPtr(unique));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -634,7 +655,7 @@ Table CreateTableWalker::table()
|
||||
do
|
||||
{
|
||||
QString col = columnname(tc);
|
||||
FieldPtr field = tab.field(tab.findField(col));
|
||||
FieldPtr field = tab->field(tab->findField(col));
|
||||
fields.push_back(field);
|
||||
|
||||
tc = tc->getNextSibling();
|
||||
@@ -666,7 +687,7 @@ Table CreateTableWalker::table()
|
||||
}
|
||||
|
||||
fk->setConstraint(concatTextAST(tc, true));
|
||||
tab.addConstraint(fields, ConstraintPtr(fk));
|
||||
tab->addConstraint(fields, ConstraintPtr(fk));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -685,15 +706,15 @@ Table CreateTableWalker::table()
|
||||
s = s->getNextSibling(); // WITHOUT
|
||||
s = s->getNextSibling(); // ROWID
|
||||
|
||||
tab.setRowidColumn(tab.fields().at(tab.findPk())->name());
|
||||
tab->setRowidColumn(tab->fields().at(tab->findPk())->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tab;
|
||||
return TablePtr(tab);
|
||||
}
|
||||
|
||||
void CreateTableWalker::parsecolumn(Table& table, antlr::RefAST c)
|
||||
void CreateTableWalker::parsecolumn(Table* table, antlr::RefAST c)
|
||||
{
|
||||
QString colname;
|
||||
QString type = "TEXT";
|
||||
@@ -832,17 +853,17 @@ void CreateTableWalker::parsecolumn(Table& table, antlr::RefAST c)
|
||||
|
||||
FieldPtr f = FieldPtr(new Field(colname, type, notnull, defaultvalue, check, unique));
|
||||
f->setAutoIncrement(autoincrement);
|
||||
table.addField(f);
|
||||
table->addField(f);
|
||||
|
||||
if(foreignKey)
|
||||
table.addConstraint({f}, ConstraintPtr(foreignKey));
|
||||
table->addConstraint({f}, ConstraintPtr(foreignKey));
|
||||
if(primaryKey)
|
||||
{
|
||||
FieldVector v;
|
||||
if(table.constraint(v, Constraint::PrimaryKeyConstraintType))
|
||||
table.primaryKeyRef().push_back(f);
|
||||
if(table->constraint(v, Constraint::PrimaryKeyConstraintType))
|
||||
table->primaryKeyRef().push_back(f);
|
||||
else
|
||||
table.addConstraint({f}, ConstraintPtr(primaryKey));
|
||||
table->addConstraint({f}, ConstraintPtr(primaryKey));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -923,7 +944,7 @@ QString Index::sql() const
|
||||
return sql + ";";
|
||||
}
|
||||
|
||||
QPair<Index, bool> Index::parseSQL(const QString& sSQL)
|
||||
QPair<ObjectPtr, bool> Index::parseSQL(const QString& sSQL)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << sSQL.toStdString();
|
||||
@@ -943,7 +964,7 @@ QPair<Index, bool> Index::parseSQL(const QString& sSQL)
|
||||
// Note: this needs to be done in two separate lines because otherwise the optimiser might decide to
|
||||
// fetch the value for the second part of the pair (the modify supported flag) first. If it does so it will
|
||||
// always be set to true because the table() method hasn't run yet and it's only set to false in there.
|
||||
sqlb::Index index = ctw.index();
|
||||
sqlb::IndexPtr index = ctw.index();
|
||||
return qMakePair(index, ctw.modifysupported());
|
||||
}
|
||||
catch(antlr::ANTLRException& ex)
|
||||
@@ -955,12 +976,12 @@ QPair<Index, bool> Index::parseSQL(const QString& sSQL)
|
||||
qCritical() << "Sqlite parse error: " << sSQL; //TODO
|
||||
}
|
||||
|
||||
return qMakePair(Index(""), false);
|
||||
return qMakePair(IndexPtr(new Index("")), false);
|
||||
}
|
||||
|
||||
Index CreateIndexWalker::index()
|
||||
IndexPtr CreateIndexWalker::index()
|
||||
{
|
||||
Index index("");
|
||||
Index* index = new Index("");
|
||||
|
||||
if(m_root) // CREATE INDEX
|
||||
{
|
||||
@@ -975,18 +996,18 @@ Index CreateIndexWalker::index()
|
||||
{
|
||||
// Is this a unique index?
|
||||
if(s->getType() == Sqlite3Lexer::UNIQUE)
|
||||
index.setUnique(true);
|
||||
index->setUnique(true);
|
||||
|
||||
s = s->getNextSibling();
|
||||
}
|
||||
|
||||
// Extract and set index name
|
||||
index.setName(tablename(s));
|
||||
index->setName(tablename(s));
|
||||
|
||||
// Get table name
|
||||
s = s->getNextSibling(); // ON
|
||||
s = s->getNextSibling(); // table name
|
||||
index.setTable(tablename(s));
|
||||
index->setTable(tablename(s));
|
||||
|
||||
s = s->getNextSibling(); // LPAREN
|
||||
s = s->getNextSibling(); // first column name
|
||||
@@ -1012,15 +1033,15 @@ Index CreateIndexWalker::index()
|
||||
m_bModifySupported = false;
|
||||
} else {
|
||||
s = s->getNextSibling(); // expr
|
||||
index.setWhereExpr(concatTextAST(s, true));
|
||||
index->setWhereExpr(concatTextAST(s, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
return IndexPtr(index);
|
||||
}
|
||||
|
||||
void CreateIndexWalker::parsecolumn(Index& index, antlr::RefAST c)
|
||||
void CreateIndexWalker::parsecolumn(Index* index, antlr::RefAST c)
|
||||
{
|
||||
QString name;
|
||||
bool isExpression;
|
||||
@@ -1074,7 +1095,7 @@ void CreateIndexWalker::parsecolumn(Index& index, antlr::RefAST c)
|
||||
c = c->getNextSibling();
|
||||
}
|
||||
|
||||
index.addColumn(IndexedColumnPtr(new IndexedColumn(name, isExpression, order)));
|
||||
index->addColumn(IndexedColumnPtr(new IndexedColumn(name, isExpression, order)));
|
||||
}
|
||||
|
||||
} //namespace sqlb
|
||||
|
||||
@@ -15,15 +15,71 @@ namespace sqlb {
|
||||
|
||||
QString escapeIdentifier(QString id);
|
||||
|
||||
class Object;
|
||||
class Table;
|
||||
class Index;
|
||||
class Field;
|
||||
class Constraint;
|
||||
class IndexedColumn;
|
||||
typedef QSharedPointer<Object> ObjectPtr;
|
||||
typedef QSharedPointer<Table> TablePtr;
|
||||
typedef QSharedPointer<Index> IndexPtr;
|
||||
typedef QSharedPointer<Field> FieldPtr;
|
||||
typedef QSharedPointer<Constraint> ConstraintPtr;
|
||||
typedef QVector<FieldPtr> FieldVector;
|
||||
typedef QSharedPointer<IndexedColumn> IndexedColumnPtr;
|
||||
typedef QVector<IndexedColumnPtr> IndexedColumnVector;
|
||||
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
enum ObjectTypes
|
||||
{
|
||||
Table,
|
||||
Index,
|
||||
View,
|
||||
Trigger
|
||||
};
|
||||
|
||||
explicit Object(const QString& name): m_name(name), m_temporary(false) {}
|
||||
virtual ~Object() {}
|
||||
|
||||
virtual ObjectTypes type() const = 0;
|
||||
|
||||
void setName(const QString& name) { m_name = name; }
|
||||
const QString& name() const { return m_name; }
|
||||
|
||||
void setOriginalSql(const QString& original_sql) { m_originalSql = original_sql; }
|
||||
QString originalSql() const { return m_originalSql; }
|
||||
|
||||
void setTemporary(bool temp) { m_temporary = temp; }
|
||||
bool isTemporary() const { return m_temporary; }
|
||||
|
||||
virtual QString baseTable() const { return QString(); }
|
||||
|
||||
virtual void clear() {}
|
||||
|
||||
/**
|
||||
* @brief Returns the CREATE statement for this object
|
||||
* @return A QString with the CREATE statement.
|
||||
*/
|
||||
virtual QString sql() const = 0;
|
||||
|
||||
/**
|
||||
* @brief parseSQL Parses the CREATE statement in sSQL.
|
||||
* @param sSQL The type of the object.
|
||||
* @param sSQL The create statement.
|
||||
* @return A pair. The first part is the parsed database object, the second a bool indicating if our
|
||||
* parser fully understood the statement. The object may be empty if parsing failed.
|
||||
*/
|
||||
static QPair<ObjectPtr, bool> parseSQL(Object::ObjectTypes type, const QString& sSQL);
|
||||
|
||||
protected:
|
||||
QString m_name;
|
||||
QString m_originalSql;
|
||||
bool m_temporary;
|
||||
};
|
||||
|
||||
class Constraint
|
||||
{
|
||||
public:
|
||||
@@ -160,15 +216,14 @@ private:
|
||||
|
||||
typedef QMultiHash<FieldVector, ConstraintPtr> ConstraintMap;
|
||||
|
||||
class Table
|
||||
class Table : public Object
|
||||
{
|
||||
public:
|
||||
explicit Table(const QString& name): m_name(name), m_rowidColumn("_rowid_"), m_temporary(false) {}
|
||||
explicit Table(const QString& name): Object(name), m_rowidColumn("_rowid_") {}
|
||||
virtual ~Table();
|
||||
|
||||
void setName(const QString& name) { m_name = name; }
|
||||
virtual ObjectTypes type() const { return Object::Table; }
|
||||
|
||||
const QString& name() const { return m_name; }
|
||||
const FieldVector& fields() const { return m_fields; }
|
||||
|
||||
/**
|
||||
@@ -192,9 +247,6 @@ public:
|
||||
QString virtualUsing() const { return m_virtual; }
|
||||
bool isVirtual() const { return !m_virtual.isEmpty(); }
|
||||
|
||||
void setTemporary(bool temp) { m_temporary = temp; }
|
||||
bool isTemporary() const { return m_temporary; }
|
||||
|
||||
void clear();
|
||||
|
||||
void addConstraint(FieldVector fields, ConstraintPtr constraint);
|
||||
@@ -224,18 +276,16 @@ public:
|
||||
* if our modify dialog supports the table.
|
||||
* The table object may be a empty table if parsing failed.
|
||||
*/
|
||||
static QPair<Table, bool> parseSQL(const QString& sSQL);
|
||||
static QPair<ObjectPtr, bool> parseSQL(const QString& sSQL);
|
||||
private:
|
||||
QStringList fieldList() const;
|
||||
bool hasAutoIncrement() const;
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
FieldVector m_fields;
|
||||
QString m_rowidColumn;
|
||||
ConstraintMap m_constraints;
|
||||
QString m_virtual;
|
||||
bool m_temporary;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -251,11 +301,11 @@ public:
|
||||
, m_bModifySupported(true)
|
||||
{}
|
||||
|
||||
Table table();
|
||||
TablePtr table();
|
||||
bool modifysupported() const { return m_bModifySupported; }
|
||||
|
||||
private:
|
||||
void parsecolumn(Table& table, antlr::RefAST c);
|
||||
void parsecolumn(Table* table, antlr::RefAST c);
|
||||
|
||||
private:
|
||||
antlr::RefAST m_root;
|
||||
@@ -291,14 +341,15 @@ private:
|
||||
QString m_order;
|
||||
};
|
||||
|
||||
class Index
|
||||
class Index : public Object
|
||||
{
|
||||
public:
|
||||
explicit Index(const QString& name): m_name(name), m_unique(false) {}
|
||||
explicit Index(const QString& name): Object(name), m_unique(false) {}
|
||||
virtual ~Index();
|
||||
|
||||
void setName(const QString& name) { m_name = name; }
|
||||
const QString& name() const { return m_name; }
|
||||
virtual ObjectTypes type() const { return Object::Index; }
|
||||
|
||||
virtual QString baseTable() const { return m_table; }
|
||||
|
||||
void setUnique(bool unique) { m_unique = unique; }
|
||||
bool unique() const { return m_unique; }
|
||||
@@ -334,10 +385,9 @@ public:
|
||||
* if our parser fully understood the statement.
|
||||
* The index object may be if parsing failed.
|
||||
*/
|
||||
static QPair<Index, bool> parseSQL(const QString& sSQL);
|
||||
static QPair<ObjectPtr, bool> parseSQL(const QString& sSQL);
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
bool m_unique;
|
||||
QString m_table;
|
||||
QString m_whereExpr;
|
||||
@@ -357,11 +407,11 @@ public:
|
||||
, m_bModifySupported(true)
|
||||
{}
|
||||
|
||||
Index index();
|
||||
IndexPtr index();
|
||||
bool modifysupported() const { return m_bModifySupported; }
|
||||
|
||||
private:
|
||||
void parsecolumn(Index& index, antlr::RefAST c);
|
||||
void parsecolumn(Index* index, antlr::RefAST c);
|
||||
|
||||
private:
|
||||
antlr::RefAST m_root;
|
||||
|
||||
Reference in New Issue
Block a user