Allow any number of changes to the table schema in one alterTable call

In the Edit Table dialog we used to call our alterTable function (which
works around SQLite's missing full ALTER TABLE support by - besided
other things - copying all the data of the table) for pretty much every
change immediately. This was taking a lot of time for larger tables.

Our alterTable function allowed any number of changes if they affect
only one field of the table at once. So we could have reduced the number
of calls a lot by just using that capability. Instead however, this
commit improves the alterTable function to make possible transforming a
table completely in just one call. It does so by taking the new table
schema and using that without further modification. It also takes a new
parameter to keep track of what column in the old table becomes what
column in the new table, so the data can be preserved.

This commit obviously also changes the Edit Table dialog to make proper
use of the new features. This means that whatever changes you make to a
table, you will only have to wait once until for the alterTable call,
and that's when clicking the OK button.

See issue #1444.
This commit is contained in:
Martin Kleusberg
2018-10-21 22:09:03 +02:00
parent 37a5645bf5
commit 9e36f21112
6 changed files with 319 additions and 266 deletions

View File

@@ -120,6 +120,18 @@ private:
antlr::RefAST m_root;
};
bool Object::operator==(const Object& rhs) const
{
if(m_name != rhs.m_name)
return false;
if(m_fullyParsed != rhs.m_fullyParsed) // We check for the fully parsed flag to make sure not to lose anything in some corner cases
return false;
// We don't care about the original SQL text
return true;
}
QString Object::typeToString(Types type)
{
switch(type)
@@ -204,6 +216,28 @@ QString CheckConstraint::toSql(const QStringList&) const
return result;
}
bool Field::operator==(const Field& rhs) const
{
if(m_name != rhs.m_name)
return false;
if(m_type != rhs.m_type)
return false;
if(m_notnull != rhs.m_notnull)
return false;
if(m_check != rhs.m_check)
return false;
if(m_defaultvalue != rhs.m_defaultvalue)
return false;
if(m_autoincrement != rhs.m_autoincrement)
return false;
if(m_unique != rhs.m_unique)
return false;
if(m_collation != rhs.m_collation)
return false;
return true;
}
QString Field::toString(const QString& indent, const QString& sep) const
{
QString str = indent + escapeIdentifier(m_name) + sep + m_type;
@@ -319,6 +353,23 @@ Table& Table::operator=(const Table& rhs)
return *this;
}
bool Table::operator==(const Table& rhs) const
{
if(!Object::operator==(rhs))
return false;
if(m_rowidColumn != rhs.m_rowidColumn)
return false;
if(m_constraints != rhs.m_constraints)
return false;
if(m_virtual != rhs.m_virtual)
return false;
if(fields != rhs.fields)
return false;
return true;
}
Table::field_iterator Table::findPk()
{
// TODO This is a stupid function (and always was) which should be fixed/improved

View File

@@ -54,6 +54,7 @@ void setIdentifierQuoting(escapeQuoting toQuoting);
QString escapeIdentifier(QString id);
std::string escapeIdentifier(std::string id);
QStringList escapeIdentifier(const QStringList& ids);
class ObjectIdentifier
{
@@ -187,6 +188,8 @@ public:
explicit Object(const QString& name): m_name(name), m_fullyParsed(false) {}
virtual ~Object() {}
virtual bool operator==(const Object& rhs) const;
virtual Types type() const = 0;
static QString typeToString(Types type);
@@ -353,10 +356,7 @@ public:
, m_collation(collation)
{}
bool operator==(const Field& rhs) const
{
return m_name == rhs.name();
}
bool operator==(const Field& rhs) const;
QString toString(const QString& indent = "\t", const QString& sep = "\t") const;
@@ -405,6 +405,8 @@ public:
~Table() override;
Table& operator=(const Table& rhs);
bool operator==(const Table& rhs) const;
Types type() const override { return Object::Table; }
FieldVector fields;
@@ -585,15 +587,22 @@ private:
template<typename T>
typename T::field_iterator findField(T* object, const QString& 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 std::find_if(object->fields.begin(), object->fields.end(), [&name](const typename T::field_type& f) {
return f.name().compare(name, Qt::CaseInsensitive) == 0;
});
}
template<typename T>
typename T::field_iterator findField(std::shared_ptr<T> object, const QString& name)
typename T::field_iterator findField(const T* object, const QString& 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)
{
return findField(object.get(), name);
}
template<typename T>
typename T::field_iterator findField(T& object, const QString& name)
typename std::remove_reference<T>::type::field_iterator findField(T& object, const QString& name)
{
return findField(&object, name);
}