summaryrefslogtreecommitdiff
path: root/odb/odb/relational/inline.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/odb/relational/inline.hxx')
-rw-r--r--odb/odb/relational/inline.hxx693
1 files changed, 693 insertions, 0 deletions
diff --git a/odb/odb/relational/inline.hxx b/odb/odb/relational/inline.hxx
new file mode 100644
index 0000000..a609cc1
--- /dev/null
+++ b/odb/odb/relational/inline.hxx
@@ -0,0 +1,693 @@
+// file : odb/relational/inline.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_RELATIONAL_INLINE_HXX
+#define ODB_RELATIONAL_INLINE_HXX
+
+#include <odb/diagnostics.hxx>
+#include <odb/relational/context.hxx>
+#include <odb/relational/common.hxx>
+
+namespace relational
+{
+ namespace inline_
+ {
+ //
+ // get/set null (composite value only)
+ //
+
+ struct null_member: virtual member_base
+ {
+ typedef null_member base;
+
+ null_member (bool get)
+ : member_base (0, 0, string (), string ()), get_ (get) {}
+
+ protected:
+ bool get_;
+ };
+
+ template <typename T>
+ struct null_member_impl: null_member, virtual member_base_impl<T>
+ {
+ typedef null_member_impl base_impl;
+
+ null_member_impl (base const& x): base (x) {}
+
+ typedef typename member_base_impl<T>::member_info member_info;
+
+ virtual bool
+ pre (member_info& mi)
+ {
+ // If the member is soft- added or deleted, check the version.
+ //
+ unsigned long long av (added (mi.m));
+ unsigned long long dv (deleted (mi.m));
+ if (av != 0 || dv != 0)
+ {
+ os << "if (";
+
+ if (av != 0)
+ os << "svm >= schema_version_migration (" << av << "ULL, true)";
+
+ if (av != 0 && dv != 0)
+ os << " &&" << endl;
+
+ if (dv != 0)
+ os << "svm <= schema_version_migration (" << dv << "ULL, true)";
+
+ os << ")"
+ << "{";
+ }
+
+ // If the whole value type is readonly, then set will never be
+ // called with sk == statement_update.
+ //
+ if (!get_ && !readonly (*context::top_object))
+ {
+ semantics::class_* c;
+
+ if (readonly (mi.m) || ((c = composite (mi.t)) && readonly (*c)))
+ os << "if (sk == statement_insert)" << endl;
+ }
+
+ return true;
+ }
+
+ virtual void
+ post (member_info& mi)
+ {
+ if (added (mi.m) || deleted (mi.m))
+ os << "}";
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ string traits ("composite_value_traits< " + mi.fq_type () + ", id_" +
+ db.string () + " >");
+
+ if (get_)
+ os << "r = r && " << traits << "::get_null (" <<
+ "i." << mi.var << "value";
+ else
+ os << traits << "::set_null (i." << mi.var << "value, sk";
+
+ if (versioned (*composite (mi.t)))
+ os << ", svm";
+
+ os << ");";
+ }
+ };
+
+ struct null_base: traversal::class_, virtual context
+ {
+ typedef null_base base;
+
+ null_base (bool get): get_ (get) {}
+
+ virtual void
+ traverse (type& c)
+ {
+ // Ignore transient bases.
+ //
+ if (!composite (c))
+ return;
+
+ string traits ("composite_value_traits< " + class_fq_name (c) +
+ ", id_" + db.string () + " >");
+
+ // If the derived value type is readonly, then set will never be
+ // called with sk == statement_update.
+ //
+ if (!get_ && readonly (c) && !readonly (*context::top_object))
+ os << "if (sk == statement_insert)" << endl;
+
+ if (get_)
+ os << "r = r && " << traits << "::get_null (i";
+ else
+ os << traits << "::set_null (i, sk";
+
+ if (versioned (c))
+ os << ", svm";
+
+ os << ");";
+ }
+
+ protected:
+ bool get_;
+ };
+
+ //
+ //
+ struct class_: traversal::class_, virtual context
+ {
+ typedef class_ base;
+
+ class_ ()
+ : typedefs_ (false),
+ get_null_base_ (true),
+ get_null_member_ (true),
+ set_null_base_ (false),
+ set_null_member_ (false)
+ {
+ init ();
+ }
+
+ class_ (class_ const&)
+ : root_context (), //@@ -Wextra
+ context (),
+ typedefs_ (false),
+ get_null_base_ (true),
+ get_null_member_ (true),
+ set_null_base_ (false),
+ set_null_member_ (false)
+ {
+ init ();
+ }
+
+ void
+ init ()
+ {
+ *this >> defines_ >> *this;
+ *this >> typedefs_ >> *this;
+
+ get_null_base_inherits_ >> get_null_base_;
+ get_null_member_names_ >> get_null_member_;
+
+ set_null_base_inherits_ >> set_null_base_;
+ set_null_member_names_ >> set_null_member_;
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ class_kind_type ck (class_kind (c));
+
+ if (ck == class_other ||
+ (!options.at_once () && class_file (c) != unit.file ()))
+ return;
+
+ names (c);
+
+ context::top_object = context::cur_object = &c;
+
+ switch (ck)
+ {
+ case class_object: traverse_object (c); break;
+ case class_view: traverse_view (c); break;
+ case class_composite: traverse_composite (c); break;
+ default: break;
+ }
+
+ context::top_object = context::cur_object = 0;
+ }
+
+ virtual void
+ object_extra (type&)
+ {
+ }
+
+ virtual void
+ traverse_object (type& c)
+ {
+ using semantics::data_member;
+
+ data_member_path* id (id_member (c));
+ data_member* idf (id ? id->front () : 0);
+ bool auto_id (id && auto_ (*id));
+ bool base_id (id && &idf->scope () != &c); // Comes from base.
+ data_member* optimistic (context::optimistic (c));
+
+ // Base class that contains the object id and version for optimistic
+ // concurrency.
+ //
+ type* base (base_id ? dynamic_cast<type*> (&idf->scope ()) : 0);
+
+ type* poly_root (context::polymorphic (c));
+ bool poly (poly_root != 0);
+ bool poly_derived (poly && poly_root != &c);
+
+ bool abst (abstract (c));
+ bool reuse_abst (abst && !poly);
+
+ bool versioned (context::versioned (c));
+
+ string const& type (class_fq_name (c));
+ string traits ("access::object_traits_impl< " + type + ", id_" +
+ db.string () + " >");
+
+ user_sections& uss (c.get<user_sections> ("user-sections"));
+
+ os << "// " << class_name (c) << endl
+ << "//" << endl
+ << endl;
+
+ object_extra (c);
+
+ if (id != 0 && base_id)
+ {
+ if (!poly_derived)
+ {
+ // id (id_image_type)
+ //
+ if (auto_id)
+ {
+ os << "inline" << endl
+ << traits << "::id_type" << endl
+ << traits << "::" << endl
+ << "id (const id_image_type& i)"
+ << "{"
+ << "return object_traits_impl< " << class_fq_name (*base) <<
+ ", id_" << db << " >::id (i);"
+ << "}";
+ }
+
+ // id (image_type)
+ //
+ if (options.generate_query ())
+ {
+ os << "inline" << endl
+ << traits << "::id_type" << endl
+ << traits << "::" << endl
+ << "id (const image_type& i)"
+ << "{"
+ << "return object_traits_impl< " << class_fq_name (*base) <<
+ ", id_" << db << " >::id (i);"
+ << "}";
+ }
+
+ // version (image_type)
+ //
+ if (optimistic != 0)
+ {
+ os << "inline" << endl
+ << traits << "::version_type" << endl
+ << traits << "::" << endl
+ << "version (const image_type& i)"
+ << "{"
+ << "return object_traits_impl< " << class_fq_name (*base) <<
+ ", id_" << db << " >::version (i);"
+ << "}";
+ }
+ }
+
+ // bind (id_image_type)
+ //
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "bind (" << bind_vector << " b, id_image_type& i" <<
+ (optimistic != 0 ? ", bool bv" : "") << ")"
+ << "{"
+ << "object_traits_impl< " << class_fq_name (*base) << ", id_" <<
+ db << " >::bind (b, i" << (optimistic != 0 ? ", bv" : "") << ");"
+ << "}";
+
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "init (id_image_type& i, const id_type& id" <<
+ (optimistic != 0 ? ", const version_type* v" : "") << ")"
+ << "{"
+ << "object_traits_impl< " << class_fq_name (*base) << ", id_" <<
+ db << " >::init (i, id" << (optimistic != 0 ? ", v" : "") << ");"
+ << "}";
+ }
+
+ if (poly_derived)
+ {
+ size_t depth (polymorphic_depth (c));
+
+ // check_version
+ //
+ os << "inline" << endl
+ << "bool " << traits << "::" << endl
+ << "check_version (const std::size_t* v, const image_type& i)"
+ << "{"
+ << "return ";
+
+ string image ("i.");
+ for (size_t i (0); i < depth; ++i)
+ {
+ os << (i == 0 ? "" : " ||") << endl
+ << " v[" << i << "UL] != " << image << "version";
+
+ image += "base->";
+ }
+
+ os << ";"
+ << "}";
+
+ // update_version
+ //
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "update_version (std::size_t* v, const image_type& i, " <<
+ db << "::binding* b)"
+ << "{";
+
+ image = "i.";
+ for (size_t i (0); i < depth; ++i)
+ {
+ os << "v[" << i << "UL] = " << image << "version;";
+ image += "base->";
+ }
+
+ // A poly-abstract class always has only one entry in the
+ // bindings array.
+ //
+ if (abst)
+ os << "b[0].version++;";
+ else
+ for (size_t i (0); i < depth; ++i)
+ os << "b[" << i << "UL].version++;";
+
+ os << "}";
+ }
+
+ // The rest does not apply to reuse-abstract objects.
+ //
+ if (reuse_abst)
+ return;
+
+ // erase (object_type)
+ //
+ if (id != 0 && !poly && optimistic == 0 &&
+ !has_a (c, test_smart_container))
+ {
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "erase (database& db, const object_type& obj)"
+ << "{"
+ << "callback (db, obj, callback_event::pre_erase);"
+ << "erase (db, id (obj));";
+
+ // Note that we don't reset sections since the object is now
+ // transient and the state of a section in a transient object
+ // is undefined.
+
+ os << "callback (db, obj, callback_event::post_erase);"
+ << "}";
+ }
+
+ // load (section) [thunk version; poly_derived is true]
+ //
+ if (uss.count (user_sections::count_total |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) != 0 &&
+ uss.count (user_sections::count_new |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) == 0)
+ {
+ os << "inline" << endl
+ << "bool " << traits << "::" << endl
+ << "load (connection& conn, object_type& obj, section& s, " <<
+ "const info_type* pi)"
+ << "{"
+ << "return base_traits::load (conn, obj, s, pi);"
+ << "}";
+ }
+
+ // update (section) [thunk version; poly_derived is true]
+ //
+ if (uss.count (user_sections::count_total |
+ user_sections::count_update |
+ (poly ? user_sections::count_update_empty : 0)) != 0 &&
+ uss.count (user_sections::count_new |
+ user_sections::count_update |
+ (poly ? user_sections::count_update_empty : 0)) == 0)
+ {
+ os << "inline" << endl
+ << "bool " << traits << "::" << endl
+ << "update (connection& conn, const object_type& obj, " <<
+ "const section& s, const info_type* pi)"
+ << "{"
+ << "return base_traits::update (conn, obj, s, pi);"
+ << "}";
+ }
+
+ // load_()
+ //
+ if (id != 0 &&
+ !(poly_derived ||
+ has_a (c, test_container | include_eager_load, &main_section) ||
+ uss.count (user_sections::count_new |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) != 0))
+ {
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "load_ (statements_type& sts," << endl
+ << "object_type& obj," << endl
+ << "bool";
+
+ if (versioned)
+ os << "," << endl
+ << "const schema_version_migration& svm";
+
+ os << ")"
+ << "{"
+ << "ODB_POTENTIALLY_UNUSED (sts);"
+ << "ODB_POTENTIALLY_UNUSED (obj);";
+
+ if (versioned)
+ os << "ODB_POTENTIALLY_UNUSED (svm);";
+
+ os << endl;
+
+ // Mark eager sections as loaded.
+ //
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ // Skip special sections.
+ //
+ if (i->special == user_section::special_version)
+ continue;
+
+ data_member& m (*i->member);
+
+ // If the section is soft- added or deleted, check the version.
+ // We can only end up here if the object itself is versioned
+ // (simple value section).
+ //
+ unsigned long long av (added (m));
+ unsigned long long dv (deleted (m));
+ if (av != 0 || dv != 0)
+ {
+ os << "if (";
+
+ if (av != 0)
+ os << "svm >= schema_version_migration (" << av << "ULL, true)";
+
+ if (av != 0 && dv != 0)
+ os << " &&" << endl;
+
+ if (dv != 0)
+ os << "svm <= schema_version_migration (" << dv << "ULL, true)";
+
+ os << ")" << endl;
+ }
+
+ // Section access is always by reference.
+ //
+ member_access& ma (m.get<member_access> ("get"));
+ if (!ma.synthesized)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ os << ma.translate ("obj") << ".reset (true, false);"
+ << endl;
+ }
+
+ os << "}";
+ }
+
+ if (poly && need_image_clone && options.generate_query ())
+ {
+ // root_image ()
+ //
+ os << "inline" << endl
+ << traits << "::root_traits::image_type&" << endl
+ << traits << "::" << endl
+ << "root_image (image_type& i)"
+ << "{";
+
+ if (poly_derived)
+ os << "return base_traits::root_image (*i.base);";
+ else
+ os << "return i;";
+
+ os << "}";
+
+ // clone_image ()
+ //
+ os << "inline" << endl
+ << traits << "::image_type*" << endl
+ << traits << "::" << endl
+ << "clone_image (image_type& i)"
+ << "{";
+
+ if (poly_derived)
+ os << "details::unique_ptr<base_traits::image_type> p (" << endl
+ << "base_traits::clone_image (*i.base));"
+ << "image_type* c (new image_type (i));"
+ << "c->base = p.release ();"
+ << "return c;";
+ else
+ os << "return new image_type (i);";
+
+ os << "}";
+
+ // copy_image ()
+ //
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "copy_image (image_type& d, image_type& s)"
+ << "{";
+
+ if (poly_derived)
+ os << "base_traits::image_type* b (d.base);"
+ << "base_traits::copy_image (*b, *s.base);"
+ << "d = s;" // Overwrites the base pointer.
+ << "d.base = b;";
+ else
+ os << "d = s;";
+
+ os << "}";
+
+ // free_image ()
+ //
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "free_image (image_type* i)"
+ << "{";
+
+ if (poly_derived)
+ os << "base_traits::free_image (i->base);";
+
+ os << "delete i;"
+ << "}";
+ }
+ }
+
+ virtual void
+ view_extra (type&)
+ {
+ }
+
+ virtual void
+ traverse_view (type& c)
+ {
+ string const& type (class_fq_name (c));
+ string traits ("access::view_traits_impl< " + type + ", id_" +
+ db.string () + " >");
+
+ os << "// " << class_name (c) << endl
+ << "//" << endl
+ << endl;
+
+ view_extra (c);
+ }
+
+ virtual void
+ traverse_composite (type& c)
+ {
+ bool versioned (context::versioned (c));
+
+ string const& type (class_fq_name (c));
+ string traits ("access::composite_value_traits< " + type + ", id_" +
+ db.string () + " >");
+
+ os << "// " << class_name (c) << endl
+ << "//" << endl
+ << endl;
+
+ if (!has_a (c, test_container))
+ {
+ // get_null (image)
+ //
+ os << "inline" << endl
+ << "bool " << traits << "::" << endl
+ << "get_null (const image_type& i";
+
+ if (versioned)
+ os << "," << endl
+ << "const schema_version_migration& svm";
+
+ os << ")"
+ << "{";
+
+ if (versioned)
+ os << "ODB_POTENTIALLY_UNUSED (svm);"
+ << endl;
+
+ os << "bool r (true);";
+
+ inherits (c, get_null_base_inherits_);
+ names (c, get_null_member_names_);
+
+ os << "return r;"
+ << "}";
+
+ // set_null (image)
+ //
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "set_null (image_type& i," << endl
+ << db << "::statement_kind sk";
+
+ if (versioned)
+ os << "," << endl
+ << "const schema_version_migration& svm";
+
+ os << ")"
+ << "{"
+ << "ODB_POTENTIALLY_UNUSED (sk);";
+
+ if (versioned)
+ os << "ODB_POTENTIALLY_UNUSED (svm);";
+
+ os << endl
+ << "using namespace " << db << ";"
+ << endl;
+
+ inherits (c, set_null_base_inherits_);
+ names (c, set_null_member_names_);
+
+ os << "}";
+ }
+ }
+
+ private:
+ traversal::defines defines_;
+ typedefs typedefs_;
+
+ instance<null_base> get_null_base_;
+ traversal::inherits get_null_base_inherits_;
+ instance<null_member> get_null_member_;
+ traversal::names get_null_member_names_;
+
+ instance<null_base> set_null_base_;
+ traversal::inherits set_null_base_inherits_;
+ instance<null_member> set_null_member_;
+ traversal::names set_null_member_names_;
+ };
+
+ struct include: virtual context
+ {
+ typedef include base;
+
+ virtual void
+ generate ()
+ {
+ if (versioned ())
+ os << "#include <odb/schema-version.hxx>" << endl
+ << endl;
+
+ if (features.polymorphic_object && options.generate_query ())
+ os << "#include <odb/details/unique-ptr.hxx>" << endl
+ << endl;
+ }
+ };
+ }
+}
+
+#endif // ODB_RELATIONAL_INLINE_HXX