parser: Extended support for NOT NULL and UNIQUE column constraints

This adds support for conflict actions in NOT NULL and UNIQUE column
constraints. It also supports named NOT NULL and UNIQUE column
constraints. With this it is now possible to edit tables which make use
of these constraints without losing any information. Adding constraints
like this via the UI is still not supported though.

Once more constraints are handled like this, the code can be probably
simplified a lot.
This commit is contained in:
Martin Kleusberg
2020-06-19 13:13:23 +02:00
parent 60f121434c
commit 1559fb3aab
6 changed files with 1614 additions and 1231 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
// A Bison parser, made by GNU Bison 3.5.1.
// A Bison parser, made by GNU Bison 3.6.3.
// Locations for Bison parsers in C++
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+21 -14
View File
@@ -36,8 +36,7 @@
type = other.type;
is_table_constraint = other.is_table_constraint;
fully_parsed = other.fully_parsed;
if(is_table_constraint)
table_constraint = other.table_constraint;
constraint = other.constraint;
text = other.text;
generated_constraint = other.generated_constraint;
@@ -66,7 +65,7 @@
bool is_table_constraint;
bool fully_parsed;
sqlb::ConstraintPtr table_constraint;
sqlb::ConstraintPtr constraint;
std::string text;
sqlb::GeneratedColumnConstraint generated_constraint;
};
@@ -691,7 +690,7 @@ columnconstraint:
sqlb::PrimaryKeyConstraint* pk = new sqlb::PrimaryKeyConstraint({sqlb::IndexedColumn("", false, $4)});
pk->setName($1);
pk->setConflictAction($5);
$$.table_constraint = sqlb::ConstraintPtr(pk);
$$.constraint = sqlb::ConstraintPtr(pk);
$$.fully_parsed = true;
}
| optional_constraintname PRIMARY KEY optional_sort_order optional_conflictclause AUTOINCREMENT {
@@ -701,13 +700,17 @@ columnconstraint:
pk->setName($1);
pk->setConflictAction($5);
pk->setAutoIncrement(true);
$$.table_constraint = sqlb::ConstraintPtr(pk);
$$.constraint = sqlb::ConstraintPtr(pk);
$$.fully_parsed = true;
}
| optional_constraintname NOT NULL optional_conflictclause {
$$.type = ColumnConstraintInfo::NotNull;
$$.is_table_constraint = false;
$$.fully_parsed = ($1 == "" && $4 == "");
sqlb::NotNullConstraint* nn = new sqlb::NotNullConstraint();
nn->setName($1);
nn->setConflictAction($4);
$$.constraint = sqlb::ConstraintPtr(nn);
$$.fully_parsed = true;
}
| optional_constraintname NULL {
$$.type = ColumnConstraintInfo::None;
@@ -717,7 +720,11 @@ columnconstraint:
| optional_constraintname UNIQUE optional_conflictclause {
$$.type = ColumnConstraintInfo::Unique;
$$.is_table_constraint = false;
$$.fully_parsed = ($1 == "" && $3 == "");
sqlb::UniqueConstraint* u = new sqlb::UniqueConstraint();
u->setName($1);
u->setConflictAction($3);
$$.constraint = sqlb::ConstraintPtr(u);
$$.fully_parsed = true;
}
| optional_constraintname CHECK "(" expr ")" {
$$.type = ColumnConstraintInfo::Check;
@@ -776,7 +783,7 @@ columnconstraint:
fk->setTable($3);
fk->setColumns($4);
fk->setConstraint($5);
$$.table_constraint = sqlb::ConstraintPtr(fk);
$$.constraint = sqlb::ConstraintPtr(fk);
$$.fully_parsed = true;
}
| optional_constraintname optional_always_generated AS "(" expr ")" optional_storage_identifier { // TODO Solve shift/reduce conflict.
@@ -809,16 +816,16 @@ columndef:
if(c.is_table_constraint)
{
if(c.table_constraint->columnList().empty())
c.table_constraint->setColumnList({$1});
if(c.constraint->columnList().empty())
c.constraint->setColumnList({$1});
else
c.table_constraint->replaceInColumnList("", $1);
table_constraints.insert(c.table_constraint);
c.constraint->replaceInColumnList("", $1);
table_constraints.insert(c.constraint);
} else {
if(c.type == ColumnConstraintInfo::NotNull) {
f.setNotNull(true);
f.setNotNull(std::dynamic_pointer_cast<sqlb::NotNullConstraint>(c.constraint));
} else if(c.type == ColumnConstraintInfo::Unique) {
f.setUnique(true);
f.setUnique(std::dynamic_pointer_cast<sqlb::UniqueConstraint>(c.constraint));
} else if(c.type == ColumnConstraintInfo::Check) {
f.setCheck(c.text);
} else if(c.type == ColumnConstraintInfo::Default) {
+25 -6
View File
@@ -174,10 +174,29 @@ std::string UniqueConstraint::toSql() const
if(!m_name.empty())
result = "CONSTRAINT " + escapeIdentifier(m_name) + " ";
std::vector<std::string> u_columns;
for(const auto& c : m_columns)
u_columns.push_back(c.toString("", " "));
result += "UNIQUE(" + joinStringVector(u_columns, ",") + ")";
result += "UNIQUE";
if(m_columns.size())
{
std::vector<std::string> u_columns;
for(const auto& c : m_columns)
u_columns.push_back(c.toString("", " "));
result += "(" + joinStringVector(u_columns, ",") + ")";
}
if(!m_conflictAction.empty())
result += " ON CONFLICT " + m_conflictAction;
return result;
}
std::string NotNullConstraint::toSql() const
{
std::string result;
if(!m_name.empty())
result = "CONSTRAINT " + escapeIdentifier(m_name) + " ";
result += "NOT NULL";
if(!m_conflictAction.empty())
result += " ON CONFLICT " + m_conflictAction;
@@ -258,13 +277,13 @@ std::string Field::toString(const std::string& indent, const std::string& sep) c
{
std::string str = indent + escapeIdentifier(m_name) + sep + m_type;
if(m_notnull)
str += " NOT NULL";
str += " " + m_notnull->toSql();
if(!m_defaultvalue.empty())
str += " DEFAULT " + m_defaultvalue;
if(!m_check.empty())
str += " CHECK(" + m_check + ")";
if(m_unique)
str += " UNIQUE";
str += " " + m_unique->toSql();
if(!m_collation.empty())
str += " COLLATE " + m_collation;
if(!m_generated.empty())
+27 -10
View File
@@ -147,6 +147,7 @@ public:
ForeignKeyConstraintType,
CheckConstraintType,
GeneratedColumnConstraintType,
NotNullConstraintType,
NoType = 999,
};
@@ -239,6 +240,22 @@ protected:
std::string m_conflictAction;
};
class NotNullConstraint : public Constraint
{
public:
void setConflictAction(const std::string& conflict) { m_conflictAction = conflict; }
const std::string& conflictAction() const { return m_conflictAction; }
std::string toSql() const override;
ConstraintTypes type() const override { return NotNullConstraintType; }
protected:
std::string m_conflictAction;
};
class PrimaryKeyConstraint : public UniqueConstraint
{
// Primary keys are a sort of unique constraint for us. This matches quite nicely as both can have a conflict action
@@ -308,8 +325,6 @@ class Field
{
public:
Field()
: m_notnull(false),
m_unique(false)
{}
Field(const std::string& name,
@@ -321,10 +336,10 @@ public:
const std::string& collation = std::string())
: m_name(name)
, m_type(type)
, m_notnull(notnull)
, m_notnull(notnull ? std::make_shared<NotNullConstraint>() : nullptr)
, m_check(check)
, m_defaultvalue(defaultvalue)
, m_unique(unique)
, m_unique(unique ? std::make_shared<UniqueConstraint>() : nullptr)
, m_collation(collation)
{}
@@ -334,10 +349,12 @@ public:
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 setNotNull(std::shared_ptr<sqlb::NotNullConstraint> notnull) { m_notnull = notnull; }
void setNotNull(bool notnull = true) { if(notnull) m_notnull = std::make_shared<NotNullConstraint>(); else m_notnull.reset(); }
void setCheck(const std::string& check) { m_check = check; }
void setDefaultValue(const std::string& defaultvalue) { m_defaultvalue = defaultvalue; }
void setUnique(bool u) { m_unique = u; }
void setUnique(std::shared_ptr<sqlb::UniqueConstraint> u) { m_unique = u; }
void setUnique(bool u) { if(u) m_unique = std::make_shared<UniqueConstraint>(); else m_unique.reset(); }
void setCollation(const std::string& collation) { m_collation = collation; }
bool isText() const;
@@ -359,10 +376,10 @@ public:
const std::string& name() const { return m_name; }
const std::string& type() const { return m_type; }
bool notnull() const { return m_notnull; }
bool notnull() const { return m_notnull ? true : false; }
const std::string& check() const { return m_check; }
const std::string& defaultValue() const { return m_defaultvalue; }
bool unique() const { return m_unique; }
bool unique() const { return m_unique ? true : false; }
const std::string& collation() const { return m_collation; }
const GeneratedColumnConstraint& generated() const { return m_generated; }
@@ -372,10 +389,10 @@ public:
private:
std::string m_name;
std::string m_type;
bool m_notnull;
std::shared_ptr<NotNullConstraint> m_notnull;
std::string m_check;
std::string m_defaultvalue;
bool m_unique;
std::shared_ptr<UniqueConstraint> m_unique;
std::string m_collation;
GeneratedColumnConstraint m_generated;
};