Skip to content

Commit

Permalink
grammar: Support named unique constraints
Browse files Browse the repository at this point in the history
Also restructure the unique constraint handling a bit to be more
parallel to the foreign key handling.

Note that this (intentionally) introduces a bit of unnecessary
code duplication which is to be eliminated in one of the next commits.
  • Loading branch information
MKleusberg committed Aug 26, 2016
1 parent ce75ccf commit 5e6900e
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 27 deletions.
77 changes: 52 additions & 25 deletions src/sqlitetypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@ QString ForeignKeyClause::toSql(const FieldVector& applyOn) const
return result;
}

QString UniqueConstraint::toSql(const FieldVector& applyOn) const
{
QString result;
if(!m_name.isNull())
result += QString("CONSTRAINT %1 ").arg(escapeIdentifier(m_name));
result += QString("UNIQUE(%1)").arg(fieldVectorToFieldNames(applyOn).join(","));

return result;
}

QString Field::toString(const QString& indent, const QString& sep) const
{
QString str = indent + escapeIdentifier(m_name) + sep + m_type;
Expand Down Expand Up @@ -154,24 +164,39 @@ void Table::setField(int index, FieldPtr f)
if(oldField)
{
// Unique constraints
for(int i=0;i<m_uniqueConstraints.size();++i)
UniqueMap::iterator it1 = m_uniqueConstraints.begin();
while(it1 != m_uniqueConstraints.end())
{
// Loop through all the fields mentioned in each unique constraint
FieldVector& constraint = m_uniqueConstraints[i];
for(int j=0;j<constraint.size();++j)
// Loop through all fields mentioned in a foreign key
FieldVector fields = it1.key();
bool modified = false;
for(int i=0;i<fields.size();++i)
{
// If the field that is being modified is in there update it to the new field
if(constraint[j] == oldField)
constraint[j] = f;
// If the field that is being modified is in there update it to the new field and set a flag that something has changed.
// This is used below to know when to update the map key
if(fields[i] == oldField)
{
fields[i] = f;
modified = true;
}
}
if(modified)
{
// When we need to update the map key, we insert a new constraint using the updated field vector and the old
// constraint information, and delete the old one afterwards
m_uniqueConstraints.insert(fields, it1.value());
it1 = m_uniqueConstraints.erase(it1);
} else {
++it1;
}
}

// Foreign keys
ForeignKeyMap::iterator it = m_foreignKeyClauses.begin();
while(it != m_foreignKeyClauses.end())
ForeignKeyMap::iterator it2 = m_foreignKeyClauses.begin();
while(it2 != m_foreignKeyClauses.end())
{
// Loop through all fields mentioned in a foreign key
FieldVector fields = it.key();
FieldVector fields = it2.key();
bool modified = false;
for(int i=0;i<fields.size();++i)
{
Expand All @@ -187,10 +212,10 @@ void Table::setField(int index, FieldPtr f)
{
// When we need to update the map key, we insert a new foreign key clause using the updated field vector and the old
// foreign key information, and delete the old one afterwards
m_foreignKeyClauses.insert(fields, it.value());
it = m_foreignKeyClauses.erase(it);
m_foreignKeyClauses.insert(fields, it2.value());
it2 = m_foreignKeyClauses.erase(it2);
} else {
++it;
++it2;
}
}
}
Expand Down Expand Up @@ -301,19 +326,21 @@ QString Table::sql() const
}

// unique constraints
foreach(FieldVector constraint, m_uniqueConstraints)
UniqueMap::const_iterator it1 = m_uniqueConstraints.constBegin();
while(it1 != m_uniqueConstraints.constEnd())
{
QStringList fieldnames = fieldVectorToFieldNames(constraint);
sql += QString(",\n\tUNIQUE(%1)").arg(fieldnames.join(","));
sql += QString(",\n\t");
sql += it1.value().toSql(it1.key());
++it1;
}

// foreign keys
ForeignKeyMap::const_iterator it = m_foreignKeyClauses.constBegin();
while(it != m_foreignKeyClauses.constEnd())
ForeignKeyMap::const_iterator it2 = m_foreignKeyClauses.constBegin();
while(it2 != m_foreignKeyClauses.constEnd())
{
sql += QString(",\n\t");
sql += it.value().toSql(it.key());
++it;
sql += it2.value().toSql(it2.key());
++it2;
}

sql += "\n)";
Expand All @@ -325,9 +352,9 @@ QString Table::sql() const
return sql + ";";
}

void Table::addUniqueConstraint(FieldVector fields)
void Table::addUniqueConstraint(FieldVector fields, UniqueConstraint unique)
{
m_uniqueConstraints.push_back(fields);
m_uniqueConstraints.insert(fields, unique);
}

void Table::addForeignKey(FieldPtr field, ForeignKeyClause fk)
Expand Down Expand Up @@ -507,8 +534,8 @@ Table CreateTableWalker::table()
break;
case sqlite3TokenTypes::UNIQUE:
{
if(!constraint_name.isNull())
m_bModifySupported = false;
UniqueConstraint unique;
unique.setName(constraint_name);

tc = tc->getNextSibling(); // skip UNIQUE
tc = tc->getNextSibling(); // skip LPAREN
Expand Down Expand Up @@ -538,7 +565,7 @@ Table CreateTableWalker::table()
if(fields.size() == 1)
fields[0]->setUnique(true);
else
tab.addUniqueConstraint(fields);
tab.addUniqueConstraint(fields, unique);
}
break;
case sqlite3TokenTypes::FOREIGN:
Expand Down
14 changes: 12 additions & 2 deletions src/sqlitetypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ QString escapeIdentifier(QString id);

class Field;
class ForeignKeyClause;
class UniqueConstraint;

typedef QSharedPointer<Field> FieldPtr;
typedef QVector< FieldPtr > FieldVector;
typedef QMap<FieldVector, ForeignKeyClause> ForeignKeyMap;
typedef QMap<FieldVector, UniqueConstraint> UniqueMap;

class Constraint
{
Expand Down Expand Up @@ -74,6 +76,14 @@ class ForeignKeyClause : public Constraint
QString m_override;
};

class UniqueConstraint : public Constraint
{
public:
UniqueConstraint() {}

virtual QString toSql(const FieldVector& applyOn) const;
};

class Field
{
public:
Expand Down Expand Up @@ -164,7 +174,7 @@ class Table
bool isWithoutRowidTable() const { return m_rowidColumn != "_rowid_"; }
void clear();

void addUniqueConstraint(FieldVector fields);
void addUniqueConstraint(FieldVector fields, UniqueConstraint unique);

void addForeignKey(FieldPtr field, ForeignKeyClause fk);
void addForeignKey(FieldVector fields, ForeignKeyClause fk);
Expand Down Expand Up @@ -198,7 +208,7 @@ class Table
QString m_name;
FieldVector m_fields;
QString m_rowidColumn;
QVector<FieldVector> m_uniqueConstraints;
UniqueMap m_uniqueConstraints;
ForeignKeyMap m_foreignKeyClauses;
};

Expand Down

0 comments on commit 5e6900e

Please sign in to comment.