Simplify the WITHOUT ROWID code a bit

In the Table class we need to store whether this is a WITHOUT ROWID
table or now. Instead of just storing a boolean flag for that we were
storing a list of the rowid column(s). This is not just more complicated
to handle than a simple flag but also more error-prone because the list
must always be kept equal to the list of primary key columns. Failing to
keep them equal would result in an invalid SQL statement.
This commit is contained in:
Martin Kleusberg
2019-04-03 12:08:58 +02:00
parent 25715bb590
commit fcac61da64
6 changed files with 28 additions and 19 deletions

View File

@@ -44,7 +44,7 @@ EditTableDialog::EditTableDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
// 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.
ui->checkWithoutRowid->blockSignals(true);
ui->checkWithoutRowid->setChecked(m_table.isWithoutRowidTable());
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
@@ -686,11 +686,11 @@ void EditTableDialog::setWithoutRowid(bool without_rowid)
}
}
// If it does, override the the rowid column names of the table object with the names of the primary keys.
m_table.setRowidColumns(pks);
// If it does, set the without rowid flag of the table
m_table.setWithoutRowidTable(true);
} else {
// If the without rowid flag is unset no further checks are required. Just set the rowid column name back to "_rowid_"
m_table.setRowidColumns({"_rowid_"});
// If the without rowid flag is unset no further checks are required. Just unset the without rowid flag
m_table.setWithoutRowidTable(false);
}
// Update the SQL preview

View File

@@ -838,7 +838,7 @@ void MainWindow::populateTable()
// Table
sqlb::TablePtr table = db.getObjectByName<sqlb::Table>(currentlyBrowsedTableName());
ui->actionUnlockViewEditing->setVisible(false);
ui->actionShowRowidColumn->setVisible(!table->isWithoutRowidTable());
ui->actionShowRowidColumn->setVisible(!table->withoutRowidTable());
} else {
// View
ui->actionUnlockViewEditing->setVisible(true);

View File

@@ -332,8 +332,8 @@ Table& Table::operator=(const Table& rhs)
// Base class
Object::operator=(rhs);
// Just assign the strings
m_rowidColumns = rhs.m_rowidColumns;
// Just assign the simple values
m_withoutRowid = rhs.m_withoutRowid;
m_virtual = rhs.m_virtual;
// Clear the fields and the constraints first in order to avoid duplicates and/or old data in the next step
@@ -354,7 +354,7 @@ bool Table::operator==(const Table& rhs) const
if(!Object::operator==(rhs))
return false;
if(m_rowidColumns != rhs.m_rowidColumns)
if(m_withoutRowid != rhs.m_withoutRowid)
return false;
if(m_virtual != rhs.m_virtual)
return false;
@@ -409,6 +409,15 @@ QStringList Table::fieldNames() const
return sl;
}
QStringList 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)
return primaryKey();
else
return {"_rowid_"};
}
FieldInfoList Table::fieldInformation() const
{
FieldInfoList result;
@@ -495,7 +504,7 @@ QString Table::sql(const QString& schema, bool ifNotExists) const
sql += "\n)";
// without rowid
if(isWithoutRowidTable())
if(withoutRowidTable())
sql += " WITHOUT ROWID";
return sql + ";";
@@ -998,7 +1007,7 @@ TablePtr CreateTableWalker::table()
s = s->getNextSibling(); // WITHOUT
s = s->getNextSibling(); // ROWID
tab->setRowidColumns(tab->primaryKey());
tab->setWithoutRowidTable(true);
}
}
}

View File

@@ -401,7 +401,7 @@ private:
class Table : public Object
{
public:
explicit Table(const QString& name): Object(name), m_rowidColumns({"_rowid_"}) {}
explicit Table(const QString& name): Object(name), m_withoutRowid(false) {}
Table& operator=(const Table& rhs);
bool operator==(const Table& rhs) const;
@@ -420,9 +420,9 @@ public:
QStringList fieldNames() const;
void setRowidColumns(const QStringList& rowid) { m_rowidColumns = rowid; }
const QStringList& rowidColumns() const { return m_rowidColumns; }
bool isWithoutRowidTable() const { return m_rowidColumns != (QStringList() << "_rowid_"); }
QStringList 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; }
@@ -453,7 +453,7 @@ private:
bool hasAutoIncrement() const;
private:
QStringList m_rowidColumns;
bool m_withoutRowid;
ConstraintMap m_constraints;
QString m_virtual;
};

View File

@@ -1309,7 +1309,7 @@ QString DBBrowserDB::addRecord(const sqlb::ObjectIdentifier& tablename)
// and adding one to it.
QString sInsertstmt;
QString pk_value;
if(table->isWithoutRowidTable())
if(table->withoutRowidTable())
{
// 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.
@@ -1324,7 +1324,7 @@ QString DBBrowserDB::addRecord(const sqlb::ObjectIdentifier& tablename)
qWarning() << "addRecord: " << lastErrorMessage;
return QString();
} else {
if(table->isWithoutRowidTable())
if(table->withoutRowidTable())
return pk_value;
else
return QString::number(sqlite3_last_insert_rowid(_db));

View File

@@ -124,7 +124,7 @@ void TestTable::withoutRowid()
f.setAutoIncrement(true);
tt.fields.push_back(f);
tt.fields.emplace_back("b", "integer");
tt.setRowidColumns({"a"});
tt.setWithoutRowidTable(true);
tt.addConstraint({f.name()}, ConstraintPtr(new PrimaryKeyConstraint()));
QCOMPARE(tt.sql(), QString("CREATE TABLE \"testtable\" (\n"