diff --git a/src/Wt/Dbo/Field.h b/src/Wt/Dbo/Field.h index 5a15c018e7..8cd4e470d6 100644 --- a/src/Wt/Dbo/Field.h +++ b/src/Wt/Dbo/Field.h @@ -16,11 +16,13 @@ namespace Wt { template class collection; namespace Impl { -const int FKNotNull = 0x01; -const int FKOnUpdateCascade = 0x02; -const int FKOnUpdateSetNull = 0x04; -const int FKOnDeleteCascade = 0x08; -const int FKOnDeleteSetNull = 0x10; +const int FKNotNull = 0x01; +const int FKOnUpdateCascade = 0x02; +const int FKOnUpdateSetNull = 0x04; +const int FKOnUpdateRestrict = 0x08; +const int FKOnDeleteCascade = 0x10; +const int FKOnDeleteSetNull = 0x20; +const int FKOnDeleteRestrict = 0x40; } /*! \brief Type that indicates one or more foreign key constraints. @@ -31,8 +33,10 @@ const int FKOnDeleteSetNull = 0x10; * \sa \link Wt::Dbo::NotNull NotNull\endlink * \sa \link Wt::Dbo::OnUpdateCascade OnUpdateCascade\endlink, * \link Wt::Dbo::OnUpdateSetNull OnUpdateSetNull\endlink + * \link Wt::Dbo::OnUpdateRestrict OnUpdateRestrict\endlink * \sa \link Wt::Dbo::OnDeleteCascade OnDeleteCascade\endlink * \link Wt::Dbo::OnDeleteSetNull OnDeleteSetNull\endlink + * \link Wt::Dbo::OnDeleteRestrict OnDeleteRestrict\endlink * * \sa belongsTo(), hasMany() * @@ -105,6 +109,23 @@ const ForeignKeyConstraint OnUpdateSetNull; const ForeignKeyConstraint OnUpdateSetNull(Impl::FKOnUpdateSetNull); #endif +/*! \brief A constraint that restricts updates. + * + * A database constraint which restricts updates to the natural primary key + * in the referenced table. + * + * \note This constraint only affects the database schema creation. Currently + * it is not possible to update a natural Id of an already saved object + * through %Dbo itself. + * + * \ingroup dbo + */ +#ifdef DOXYGEN_ONLY +const ForeignKeyConstraint OnUpdateRestrict; +#else +const ForeignKeyConstraint OnUpdateRestrict(Impl::FKOnUpdateRestrict); +#endif + /*! \brief A constraint that cascades deletes. * * A database constraint which propagates deletes of the referenced object @@ -135,6 +156,21 @@ const ForeignKeyConstraint OnDeleteSetNull; const ForeignKeyConstraint OnDeleteSetNull(Impl::FKOnDeleteSetNull); #endif +/*! \brief A constraint that restricts deletes. + * + * A database constraint which restricts deletes of the referenced object + * to also restrict deletion of the objects that reference. + * + * \note This constraint only affects the database schema creation. + * + * \ingroup dbo + */ +#ifdef DOXYGEN_ONLY +const ForeignKeyConstraint OnDeleteRestrict; +#else +const ForeignKeyConstraint OnDeleteRestrict(Impl::FKOnDeleteRestrict); +#endif + class Session; class SqlStatement; diff --git a/src/Wt/Dbo/Session.C b/src/Wt/Dbo/Session.C index a2a0df6ec8..5ff75a63f2 100644 --- a/src/Wt/Dbo/Session.C +++ b/src/Wt/Dbo/Session.C @@ -908,11 +908,16 @@ std::string Session::constraintString(Impl::MappingInfo *mapping, else if (field.fkConstraints() & Impl::FKOnUpdateSetNull && haveSupportUpdateCascade_) sql << " on update set null"; + else if (field.fkConstraints() & Impl::FKOnUpdateRestrict + && haveSupportUpdateCascade_) + sql << " on update restrict"; if (field.fkConstraints() & Impl::FKOnDeleteCascade) sql << " on delete cascade"; else if (field.fkConstraints() & Impl::FKOnDeleteSetNull) sql << " on delete set null"; + else if (field.fkConstraints() & Impl::FKOnDeleteRestrict) + sql << " on delete restrict"; if (connection(false)->supportDeferrableFKConstraint()) //backend condition sql << " deferrable initially deferred"; diff --git a/test/dbo/DboTest8.C b/test/dbo/DboTest8.C new file mode 100644 index 0000000000..d200c31d32 --- /dev/null +++ b/test/dbo/DboTest8.C @@ -0,0 +1,74 @@ +#define BOOST_TEST_MODULE Foreign Key Constraint + +#include +#include +#include +#include + +namespace dbo = Wt::Dbo; + +class TableSrc1 +{ + public: + + template + void persist([[maybe_unused]] Action &a) + { + } +}; + +class TableSrc2 +{ + public: + + template + void persist([[maybe_unused]] Action &a) + { + } +}; + +class TableDst +{ + public: + dbo::ptr table_src1; + dbo::ptr table_src2; + + template + void persist(Action &a) + { + dbo::belongsTo(a, table_src1, dbo::OnDeleteRestrict); + dbo::belongsTo(a, table_src2, dbo::OnUpdateRestrict); + } +}; + +BOOST_AUTO_TEST_CASE(foreign_key_constraints_test) +{ + dbo::Session session; + auto conn = std::make_unique(":memory:"); + session.setConnection(std::move(conn)); + + session.mapClass("table_src1"); + session.mapClass("table_src2"); + session.mapClass("table_dst"); + + auto sql = session.tableCreationSql(); + + std::string needle_del_restrict = "on delete restrict"; + const auto it_del_restrict = std::search(begin(sql), end(sql), begin(needle_del_restrict), end(needle_del_restrict)); + BOOST_REQUIRE((it_del_restrict != cend(sql))); + + std::string needle_update_restrict = "on update restrict"; + const auto it_update_restrict = std::search(begin(sql), end(sql), begin(needle_update_restrict), end(needle_update_restrict)); + BOOST_REQUIRE((it_update_restrict != cend(sql))); + + try + { + session.createTables(); + BOOST_REQUIRE(true); + } + catch(...) + { + BOOST_REQUIRE(false); + } + +}