// file : odb/relational/header.cxx // copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC // license : GNU GPL v3; see accompanying LICENSE file #include #include using namespace std; void relational::header::class1:: traverse_object (type& c) { using semantics::data_member; data_member* id (id_member (c)); bool auto_id (id && auto_ (*id)); bool base_id (id && &id->scope () != &c); // Comes from base. data_member* optimistic (context::optimistic (c)); type* poly_root (polymorphic (c)); bool poly (poly_root != 0); bool poly_derived (poly && poly_root != &c); data_member* discriminator (poly ? context::discriminator (*poly_root) : 0); bool abst (abstract (c)); bool reuse_abst (abst && !poly); bool versioned (context::versioned (c)); string const& type (class_fq_name (c)); // Sections. // user_sections& uss (c.get ("user-sections")); os << "// " << class_name (c) << endl << "//" << endl; // pointer_query_columns & query_columns // if (options.generate_query ()) { // If we don't have object pointers, then also generate // query_columns (in this case pointer_query_columns and // query_columns are the same and the former inherits from // the latter). Otherwise we have to postpone query_columns // generation until the second pass to deal with forward- // declared objects. // if (!has_a (c, test_pointer | include_base)) query_columns_type_->traverse (c); pointer_query_columns_type_->traverse (c); } // object_traits_impl // os << "template <>" << endl << "class " << exp << "access::object_traits_impl< " << type << ", " << "id_" << db << " >:" << endl << " public access::object_traits< " << type << " >" << "{" << "public:" << endl; object_public_extra_pre (c); // For dynamic multi-database support also generate common traits // alias (used in query aliasing). // if (options.generate_query () && multi_dynamic) { os << "typedef access::object_traits_impl< " << type << ", " << "id_common > common_traits;" << endl; } // Polymorphic root_traits, base_traits, and discriminator_image_type. // if (poly) { if (!abst) os << "typedef polymorphic_entry entry_type;"; os << "typedef object_traits_impl " << "root_traits;"; if (poly_derived) { os << "typedef object_traits_impl " << "base_traits;" << endl; } else { os << endl << "struct discriminator_image_type" << "{"; discriminator_image_member_->traverse (*discriminator); if (optimistic != 0) version_image_member_->traverse (*optimistic); os << "std::size_t version;" << "};"; } } // id_image_type // if (id != 0) { if (base_id) { if (poly_derived) os << "typedef root_traits::id_image_type id_image_type;" << endl; else { semantics::class_& b ( dynamic_cast (id->scope ())); os << "typedef object_traits_impl< " << class_fq_name (b) << ", " << "id_" << db << " >::id_image_type id_image_type;" << endl; } } else { os << "struct id_image_type" << "{"; id_image_member_->traverse (*id); if (optimistic != 0) version_image_member_->traverse (*optimistic); os << "std::size_t version;" << "};"; } } // Polymorphic map. // if (poly) { if (!poly_derived) os << "static map_type* map;"; os << "static const " << (abst ? "abstract_" : "") << "info_type info;" << endl; } // image_type // image_type_->traverse (c); // Extra (container, section) statement cache (forward declaration). // if (!reuse_abst && id != 0) os << "struct extra_statement_cache_type;" << endl; // // Containers (abstract and concrete). // { instance t (c); t->traverse (c); } // // Sections (abstract and concrete). // for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) { instance t (c); t->traverse (*i); } // // Query (abstract and concrete). // if (options.generate_query ()) { // Generate object pointer tags here unless we are generating dynamic // multi-database support, in which case they generated in object_traits. // if (!multi_dynamic && has_a (c, test_pointer | exclude_base)) { query_tags t; // Not customizable. t.traverse (c); } } // // Functions (abstract and concrete). // if (id != 0 || !reuse_abst) os << "using object_traits::id;" << endl; if (!poly_derived && id != 0) { if (options.generate_query ()) os << "static id_type" << endl << "id (const image_type&);" << endl; if (optimistic != 0) os << "static version_type" << endl << "version (const image_type&);" << endl; } // discriminator() // if (poly && !poly_derived) os << "static discriminator_type" << endl << "discriminator (const image_type&);" << endl; // grow () // if (generate_grow) { // For derived classes in a polymorphic hierarchy, grow() will // check bases up to the specified depth. If one of the base // images has grown, then it will increment its version. But // the return value only indicates the state of this image, // excluding polymorphic bases (in other words, it is possible // that one of the bases has grown but this function returns // false). // os << "static bool" << endl << "grow (image_type&," << endl << truncated_vector; if (versioned) os << "," << endl << "const schema_version_migration&"; if (poly_derived) os << "," << endl << "std::size_t = depth"; os << ");" << endl; } // bind (image_type) // os << "static void" << endl << "bind (" << bind_vector << "," << endl; // If we are a derived type in a polymorphic hierarchy, then // we get the the external id binding. // if (poly_derived) os << "const " << bind_vector << " id," << endl << "std::size_t id_size," << endl; os << "image_type&," << endl << db << "::statement_kind"; if (versioned) os << "," << endl << "const schema_version_migration&"; os << ");" << endl; // bind (id_image_type) // if (id != 0) { os << "static void" << endl << "bind (" << bind_vector << ", id_image_type&" << (optimistic != 0 ? ", bool bind_version = true" : "") << ");" << endl; } // init (image, object) // os << "static " << (generate_grow ? "bool" : "void") << endl << "init (image_type&," << endl << "const object_type&," << endl << db << "::statement_kind"; if (versioned) os << "," << endl << "const schema_version_migration&"; os << ");" << endl; // init (object, image) // os << "static void" << endl << "init (object_type&," << endl << "const image_type&," << endl << "database*"; if (versioned) os << "," << endl << "const schema_version_migration&"; if (poly_derived) os << "," << endl << "std::size_t = depth"; os << ");" << endl; // init (id_image, id) // if (id != 0) { os << "static void" << endl << "init (id_image_type&, const id_type&" << (optimistic != 0 ? ", const version_type* = 0" : "") << ");" << endl; } if (poly_derived) { // check_version // os << "static bool" << endl << "check_version (const std::size_t*, const image_type&);" << endl; // update_version // os << "static void" << endl << "update_version (std::size_t*, const image_type&, " << db << "::binding*);" << endl; } // The rest does not apply to reuse-abstract objects. // if (reuse_abst) { object_public_extra_post (c); os << "};"; return; } column_count_type const& cc (column_count (c)); // Statements typedefs. // if (poly) { if (poly_derived) os << "typedef" << endl << db << "::polymorphic_derived_object_statements" << "" << endl << "statements_type;" << endl << "typedef" << endl << db << "::polymorphic_root_object_statements" << endl << "root_statements_type;" << endl; else os << "typedef" << endl << db << "::polymorphic_root_object_statements" << endl << "statements_type;" << endl << "typedef statements_type root_statements_type;" << endl; } else { if (id != 0) os << "typedef " << db << "::object_statements " << "statements_type;" << endl; else os << "typedef " << db << "::no_id_object_statements " << "statements_type;" << endl; } // // Query (concrete). // if (options.generate_query ()) { // query_base_type // os << "typedef " << db << "::query_base query_base_type;" << endl; } // // Containers (concrete). // // // Sections (concrete). // // column_count // os << "static const std::size_t column_count = " << cc.total << "UL;" << "static const std::size_t id_column_count = " << cc.id << "UL;" << "static const std::size_t inverse_column_count = " << cc.inverse << "UL;" << "static const std::size_t readonly_column_count = " << cc.readonly << "UL;" << "static const std::size_t managed_optimistic_column_count = " << cc.optimistic_managed << "UL;"; if (poly && !poly_derived) os << "static const std::size_t discriminator_column_count = " << cc.discriminator << "UL;"; os << endl << "static const std::size_t separate_load_column_count = " << cc.separate_load << "UL;" << "static const std::size_t separate_update_column_count = " << cc.separate_update << "UL;" << endl; os << "static const bool versioned = " << versioned << ";" << endl; // Statements. // os << "static const char persist_statement[];"; if (id != 0) { if (poly_derived) { char const* n (abst ? "1" : "depth"); os << "static const char* const find_statements[" << n << "];" << "static const std::size_t find_column_counts[" << n << "];"; } else { os << "static const char find_statement[];"; if (poly) os << "static const char find_discriminator_statement[];"; } if (cc.total != cc.id + cc.inverse + cc.readonly + cc.separate_update) os << "static const char update_statement[];"; os << "static const char erase_statement[];"; if (optimistic != 0 && !poly_derived) os << "static const char optimistic_erase_statement[];"; } if (options.generate_query ()) { os << "static const char query_statement[];" << "static const char erase_query_statement[];" << endl << "static const char table_name[];"; } os << endl; // // Functions (concrete). // // persist () // os << "static void" << endl << "persist (database&, " << (auto_id ? "" : "const ") << "object_type&"; if (poly) os << ", bool top = true, bool dyn = true"; os << ");" << endl; if (id != 0) { // find (id) // if (c.default_ctor ()) os << "static pointer_type" << endl << "find (database&, const id_type&);" << endl; // find (id, obj) // os << "static bool" << endl << "find (database&, const id_type&, object_type&"; if (poly) os << ", bool dyn = true"; os << ");" << endl; // reload () // os << "static bool" << endl << "reload (database&, object_type&"; if (poly) os << ", bool dyn = true"; os << ");" << endl; // update () // // In case of a polymorphic object, we generate update() even if it is // readonly since the potentially-readwrite base will rely on it to // initialize the id image. // // if (!readonly (c) || poly) { os << "static void" << endl << "update (database&, const object_type&"; if (poly) os << ", bool top = true, bool dyn = true"; os << ");" << endl; } // erase () // os << "static void" << endl << "erase (database&, const id_type&"; if (poly) os << ", bool top = true, bool dyn = true"; os << ");" << endl; os << "static void" << endl << "erase (database&, const object_type&"; if (poly) os << ", bool top = true, bool dyn = true"; os << ");" << endl; // Sections. // // We treat all polymorphic sections as (potentially) having something // to load or to update since we cannot predict what will be added to // them in overrides. // if (uss.count (user_sections::count_total | user_sections::count_load | (poly ? user_sections::count_load_empty : 0)) != 0) os << "static bool" << endl << "load (connection&, object_type&, section&" << (poly ? ", const info_type* = 0" : "") << ");" << endl; if (uss.count (user_sections::count_total | user_sections::count_update | (poly ? user_sections::count_update_empty : 0)) != 0) os << "static bool" << endl << "update (connection&, const object_type&, const section&" << (poly ? ", const info_type* = 0" : "") << ");" << endl; } // query () // if (options.generate_query ()) { if (!options.omit_unprepared ()) { os << "static result" << endl << "query (database&, const query_base_type&);" << endl; if (multi_dynamic) os << "static result" << endl << "query (database&, const odb::query_base&);" << endl; } os << "static unsigned long long" << endl << "erase_query (database&, const query_base_type&);" << endl; if (multi_dynamic) os << "static unsigned long long" << endl << "erase_query (database&, const odb::query_base&);" << endl; if (options.generate_prepared ()) { os << "static odb::details::shared_ptr" << endl << "prepare_query (connection&, const char*, const query_base_type&);" << endl; if (multi_dynamic) os << "static odb::details::shared_ptr" << endl << "prepare_query (connection&, const char*, " << "const odb::query_base&);" << endl; os << "static odb::details::shared_ptr" << endl << "execute_query (prepared_query_impl&);" << endl; } } object_public_extra_post (c); // Implementation details. // os << "public:" << endl; if (id != 0) { // Load the object image. // os << "static bool" << endl << "find_ (statements_type&," << endl << "const id_type*"; if (versioned) os << "," << endl << "const schema_version_migration&"; if (poly_derived && !abst) os << "," << endl << "std::size_t = depth"; os << ");" << endl; // Load the rest of the object (containers, etc). Expects the id // image in the object statements to be initialized to the object // id. // os << "static void" << endl << "load_ (statements_type&," << endl << "object_type&," << endl << "bool reload"; if (versioned) os << "," << endl << "const schema_version_migration&"; if (poly_derived) os << "," << endl << "std::size_t = depth"; os << ");" << endl; } // discriminator_ () // if (poly && !poly_derived) { os << "static void" << endl << "discriminator_ (statements_type&," << endl << "const id_type&," << endl << "discriminator_type*"; if (optimistic != 0) os << "," << endl << "version_type* = 0"; os << ");" << endl; } // Load the dynamic part of the object. Depth inidicates where // the dynamic part starts. Expects the id image in the object // statements to be initialized to the object id. We don't need // it if we are poly-abstract. // if (poly_derived && !abst) os << "static void" << endl << "load_ (database&, root_type&, std::size_t);" << endl; // Image chain manipulation. // if (poly && need_image_clone && options.generate_query ()) { os << "static root_traits::image_type&" << endl << "root_image (image_type&);" << endl; // Note that the original image is non-const since for some databases // the copy "steals" stuff from the original (e.g., LOB descriptors in // Oracle). // os << "static image_type*" << endl << "clone_image (image_type&);" << endl; os << "static void" << endl << "copy_image (image_type&, image_type&);" << endl; os << "static void" << endl << "free_image (image_type*);" << endl; } os << "};"; // object_traits_impl< , id_common> // // Note that it is not generated for reuse-abstract classes. // if (options.default_database_specified () && options.default_database () == db) { os << "template <>" << endl << "class access::object_traits_impl< " << type << ", " << "id_common >:" << endl << " public access::object_traits_impl< " << type << ", " << "id_" << db << " >" << "{" << "};"; } } void relational::header::class1:: traverse_view (type& c) { bool versioned (context::versioned (c)); string const& type (class_fq_name (c)); size_t obj_count (c.get ("object-count")); os << "// " << class_name (c) << endl << "//" << endl; // view_traits_impl // os << "template <>" << endl << "class " << exp << "access::view_traits_impl< " << type << ", " << "id_" << db << " >:" << endl << " public access::view_traits< " << type << " >" << "{" << "public:" << endl; view_public_extra_pre (c); // For dynamic multi-database support also generate common traits // alias (used in query aliasing). // if (multi_dynamic) { os << "typedef access::view_traits_impl< " << type << ", " << "id_common > common_traits;" << endl; } // image_type // image_type_->traverse (c); os << "typedef " << db << "::view_statements statements_type;" << endl; // // Query. // // Generate associated object tags here unless we are generating dynamic // multi-database support, in which case they generated in object_traits. // if (!multi_dynamic) { query_tags t; // Not customizable. t.traverse (c); } // query_base_type and query_columns (definition generated by class2). // os << "typedef " << db << "::query_base query_base_type;" << "struct query_columns"; if (obj_count == 0) os << "{" << "};"; else os << ";" << endl; os << "static const bool versioned = " << versioned << ";" << endl; // // Functions. // // grow () // if (generate_grow) { os << "static bool" << endl << "grow (image_type&," << endl << truncated_vector; if (versioned) os << "," << endl << "const schema_version_migration&"; os << ");" << endl; } // bind (image_type) // os << "static void" << endl << "bind (" << bind_vector << "," << endl << "image_type&"; if (versioned) os << "," << endl << "const schema_version_migration&"; os << ");" << endl; // init (view, image) // os << "static void" << endl << "init (view_type&," << endl << "const image_type&," << endl << "database*"; if (versioned) os << "," << endl << "const schema_version_migration&"; os << ");" << endl; // column_count // os << "static const std::size_t column_count = " << column_count (c).total << "UL;" << endl; // Statements. // view_query& vq (c.get ("query")); if (vq.kind != view_query::runtime) { os << "static query_base_type" << endl << "query_statement (const query_base_type&);" << endl; } // // Functions. // // query () // if (!options.omit_unprepared ()) { os << "static result" << endl << "query (database&, const query_base_type&);" << endl; if (multi_dynamic) os << "static result" << endl << "query (database&, const odb::query_base&);" << endl; } if (options.generate_prepared ()) { os << "static odb::details::shared_ptr" << endl << "prepare_query (connection&, const char*, const query_base_type&);" << endl; if (multi_dynamic) os << "static odb::details::shared_ptr" << endl << "prepare_query (connection&, const char*, " << "const odb::query_base&);" << endl; os << "static odb::details::shared_ptr" << endl << "execute_query (prepared_query_impl&);" << endl; } view_public_extra_post (c); os << "};"; // view_traits_impl< , id_common> // if (options.default_database_specified () && options.default_database () == db) { os << "template <>" << endl << "class access::view_traits_impl< " << type << ", " << "id_common >:" << endl << " public access::view_traits_impl< " << type << ", " << "id_" << db << " >" << "{" << "};"; } } void relational::header::class1:: traverse_composite (type& c) { bool versioned (context::versioned (c)); string const& type (class_fq_name (c)); os << "// " << class_name (c) << endl << "//" << endl; // While composite_value_traits is not used directly by user code, we // still need to export it if the generated code for the same database // is split into several DLLs. // os << "template <>" << endl << "class " << exp << "access::composite_value_traits< " << type << ", id_" << db << " >" << "{" << "public:" << endl; // value_type // os << "typedef " << type << " value_type;" << endl; // image_type // image_type_->traverse (c); // Containers. // { instance t (c); t->traverse (c); } // grow () // if (generate_grow) { os << "static bool" << endl << "grow (image_type&," << endl << truncated_vector; if (versioned) os << "," << endl << "const schema_version_migration&"; os << ");" << endl; } // bind (image_type) // os << "static void" << endl << "bind (" << bind_vector << "," << endl << "image_type&," << endl << db << "::statement_kind"; if (versioned) os << "," << endl << "const schema_version_migration&"; os << ");" << endl; // init (image, value) // os << "static " << (generate_grow ? "bool" : "void") << endl << "init (image_type&," << endl << "const value_type&," << endl << db << "::statement_kind"; if (versioned) os << "," << endl << "const schema_version_migration&"; os << ");" << endl; // init (value, image) // os << "static void" << endl << "init (value_type&," << endl << "const image_type&," << endl << "database*"; if (versioned) os << "," << endl << "const schema_version_migration&"; os << ");" << endl; if (!has_a (c, test_container)) { // get_null (image) // os << "static bool" << endl << "get_null (const image_type&"; if (versioned) os << "," << endl << "const schema_version_migration&"; os << ");" << endl; // set_null (image) // os << "static void" << endl << "set_null (image_type&," << endl << db << "::statement_kind"; if (versioned) os << "," << endl << "const schema_version_migration&"; os << ");" << endl; } os << "};"; } void relational::header:: generate () { context ctx; ostream& os (ctx.os); instance i; i->generate (); os << "namespace odb" << "{"; { traversal::unit unit; traversal::defines unit_defines; typedefs unit_typedefs (false); traversal::namespace_ ns; instance c; unit >> unit_defines >> ns; unit_defines >> c; unit >> unit_typedefs >> c; traversal::defines ns_defines; typedefs ns_typedefs (false); ns >> ns_defines >> ns; ns_defines >> c; ns >> ns_typedefs >> c; unit.dispatch (ctx.unit); } { traversal::unit unit; traversal::defines unit_defines; typedefs unit_typedefs (false); traversal::namespace_ ns; instance c; unit >> unit_defines >> ns; unit_defines >> c; unit >> unit_typedefs >> c; traversal::defines ns_defines; typedefs ns_typedefs (false); ns >> ns_defines >> ns; ns_defines >> c; ns >> ns_typedefs >> c; unit.dispatch (ctx.unit); } os << "}"; }