From f6eda10b4014ea75af1be88ab3498618e390ea47 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 16 Sep 2013 08:20:00 +0200 Subject: Diagnose (potentially) empty UPDATE statements with ROWVERSION --- odb/common.cxx | 26 ++++++++++++++++++++++++-- odb/common.hxx | 8 ++++++++ odb/relational/mssql/source.cxx | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/odb/common.cxx b/odb/common.cxx index 365fe19..f52cee6 100644 --- a/odb/common.cxx +++ b/odb/common.cxx @@ -270,12 +270,24 @@ traverse_view (semantics::class_& c) } void object_columns_base:: +traverse_pre (semantics::nameable&) +{ +} + +void object_columns_base:: +traverse_post (semantics::nameable&) +{ +} + +void object_columns_base:: traverse (semantics::data_member& m, semantics::type& t, std::string const& kp, std::string const& dn, semantics::class_* to) { + traverse_pre (m); + semantics::class_* oto (context::top_object); if (to != 0) @@ -305,6 +317,8 @@ traverse (semantics::data_member& m, root_ = 0; context::top_object = oto; + + traverse_post (m); } void object_columns_base:: @@ -320,7 +334,10 @@ traverse (semantics::class_& c) bool f (top_level_); if (top_level_) + { + traverse_pre (c); top_level_ = false; + } else { // Unless requested otherwise, don't go into bases if we are a derived @@ -365,8 +382,13 @@ traverse (semantics::class_& c) context::top_object = 0; } - if (f && !first_) - flush (); + if (f) + { + if (!first_) + flush (); + + traverse_post (c); + } } void object_columns_base:: diff --git a/odb/common.hxx b/odb/common.hxx index c4ecbaf..0fcd481 100644 --- a/odb/common.hxx +++ b/odb/common.hxx @@ -219,6 +219,14 @@ struct object_columns_base: traversal::class_, virtual context virtual bool section_test (data_member_path const&); + // Start/end traversal callbacks. + // + virtual void + traverse_pre (semantics::nameable&); + + virtual void + traverse_post (semantics::nameable&); + public: object_columns_base (bool first = true, column_prefix const& cp = column_prefix (), diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx index 8274b50..83096ab 100644 --- a/odb/relational/mssql/source.cxx +++ b/odb/relational/mssql/source.cxx @@ -35,7 +35,8 @@ namespace relational // struct object_columns: relational::object_columns, context { - object_columns (base const& x): base (x) {} + object_columns (base const& x) + : base (x), rowversion_ (false), column_count_ (0) {} virtual bool column (semantics::data_member& m, @@ -55,11 +56,39 @@ namespace relational { sql_type t (parse_sql_type (column_type (), m)); if (t.type == sql_type::ROWVERSION) + { + rowversion_ = true; return false; + } } - return base::column (m, table, column); + bool r (base::column (m, table, column)); + + // Count the number of columns in the UPDATE statement, but + // excluding soft-deleted. + // + if (sk_ == statement_update && r && !deleted (member_path_)) + column_count_++; + + return r; + } + + virtual void + traverse_post (semantics::nameable& n) + { + if (rowversion_ && column_count_ == 0) + { + location l (n.location ()); + error (l) << "ROWVERSION in an object without any readwrite " + "data members" << endl; + error (l) << "UPDATE statement will be empty" << endl; + throw operation_failed (); + } } + + private: + bool rowversion_; + size_t column_count_; }; entry object_columns_; -- cgit v1.1