From 823026b58211a4166de06ac243d978dcb9930271 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Mon, 22 Jan 2024 15:58:08 +0300 Subject: Turn odb repository into muti-package repository Also remove the autoconf/make-based build system. --- odb/relational/source.hxx | 7154 --------------------------------------------- 1 file changed, 7154 deletions(-) delete mode 100644 odb/relational/source.hxx (limited to 'odb/relational/source.hxx') diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx deleted file mode 100644 index 3c6f5da..0000000 --- a/odb/relational/source.hxx +++ /dev/null @@ -1,7154 +0,0 @@ -// file : odb/relational/source.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_SOURCE_HXX -#define ODB_RELATIONAL_SOURCE_HXX - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -namespace relational -{ - namespace source - { - // Column literal in a statement (e.g., in select-list, etc). - // - struct statement_column - { - statement_column (): member (0) {} - statement_column (std::string const& tbl, - std::string const& col, - std::string const& t, - semantics::data_member& m, - std::string const& kp = "") - : table (tbl), column (col), type (t), member (&m), key_prefix (kp) - { - } - - std::string table; // Schema-qualifed and quoted table name. - std::string column; // Table-qualifed and quoted column expr. - std::string type; // Column SQL type. - semantics::data_member* member; - std::string key_prefix; - }; - - typedef std::list statement_columns; - - // Query parameter generator. A new instance is created for each - // query, so the customized version can have a counter to implement, - // for example, numbered parameters (e.g., $1, $2, etc). The auto_id() - // function is called instead of next() for the automatically-assigned - // object id member when generating the persist statement. If empty - // string is returned, then parameter is ignored. - // - struct query_parameters: virtual context - { - typedef query_parameters base; - - query_parameters (statement_kind sk, qname const& table) - : sk_ (sk), table_ (table) {} - - virtual string - next (semantics::data_member&, - const std::string& /*column*/, // Table qualified and quoted. - const std::string& /*sqlt*/) - { - return "?"; - } - - virtual string - auto_id (semantics::data_member& m, - const std::string& column, - const std::string& sqlt) - { - return next (m, column, sqlt); - } - - string - next (const object_columns_list::column& c) - { - return next (*c.member, quote_id (c.name), c.type); - } - - string - next (const statement_column& c) - { - return next (*c.member, c.column, c.type); - } - - protected: - statement_kind sk_; - qname table_; - }; - - struct object_columns: object_columns_base, virtual context - { - typedef object_columns base; - - // If provided, used to resolve table/alias names for inverse - // pointed-to and base objects. Returns qualified name. - // - struct table_name_resolver - { - virtual string - resolve_pointer (semantics::data_member&) const = 0; - - virtual string - resolve_base (semantics::class_&) const = 0; - }; - - object_columns (statement_kind sk, - statement_columns& sc, - query_parameters* param = 0, - object_section* section = 0) - : object_columns_base (true, true, section), - sk_ (sk), - ro_ (true), - sc_ (sc), - param_ (param), - table_name_resolver_ (0), - depth_ (1) - { - } - - object_columns (statement_kind sk, - bool ignore_ro, - statement_columns& sc, - query_parameters* param) - : object_columns_base (true, true, 0), - sk_ (sk), - ro_ (ignore_ro), - sc_ (sc), - param_ (param), - table_name_resolver_ (0), - depth_ (1) - { - } - - object_columns (std::string const& table_qname, - statement_kind sk, - statement_columns& sc, - size_t depth = 1, - object_section* section = 0, - table_name_resolver* tnr = 0) - : object_columns_base (true, true, section), - sk_ (sk), - ro_ (true), - sc_ (sc), - param_ (0), - table_name_ (table_qname), - table_name_resolver_ (tnr), - depth_ (depth) - { - } - - virtual bool - section_test (data_member_path const& mp) - { - object_section& s (section (mp)); - - // Include eager loaded members into the main section for - // SELECT statements. Also include optimistic version into - // section's SELECT and UPDATE statements. - // - return section_ == 0 || - *section_ == s || - (sk_ == statement_select && - *section_ == main_section && - !s.separate_load ()) || - (version (mp) && - (sk_ == statement_update || sk_ == statement_select)); - } - - virtual void - traverse_object (semantics::class_& c) - { - // If we are generating a select statement and this is a derived - // type in a polymorphic hierarchy, then we need to include base - // columns, but do it in reverse order as well as switch the table - // name (base columns come from different tables). - // - semantics::class_* poly_root (polymorphic (c)); - if (poly_root != 0 && poly_root != &c) - { - names (c); - - if (sk_ == statement_select && --depth_ != 0) - { - semantics::class_& b (polymorphic_base (c)); - - table_name_ = table_name_resolver_ != 0 - ? table_name_resolver_->resolve_base (b) - : table_qname (b); - - inherits (c); - } - } - else - object_columns_base::traverse_object (c); - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - // Ignore polymorphic id references for select statements. - // - if (sk_ == statement_select && m.count ("polymorphic-ref")) - return; - - data_member_path* imp (inverse (m, key_prefix_)); - - // Ignore certain columns depending on what kind of statement we are - // generating. Columns corresponding to the inverse members are - // only present in the select statements. - // - if (imp != 0 && sk_ != statement_select) - return; - - // Inverse object pointers come from a joined table. - // - if (imp != 0) - { - bool poly (polymorphic (c) != 0); - semantics::data_member& imf (*imp->front ()); - semantics::data_member& imb (*imp->back ()); - - // In a polymorphic hierarchy the inverse member can be in - // the base class, in which case we should use that table. - // - semantics::class_& imc ( - poly ? dynamic_cast (imf.scope ()) : c); - - data_member_path& id (*id_member (imc)); - semantics::type& idt (utype (id)); - - if (container (imb)) - { - // This container is a direct member of the class so the table - // prefix is just the class table name. We don't assign join - // aliases for container tables so use the actual table name. - // Note that the if(!table_name_.empty ()) test may look wrong - // at first but it is not; if table_name_ is empty then we are - // generating a container table where we don't qualify columns - // with tables. - // - string table; - - if (!table_name_.empty ()) - { - if (table_name_resolver_ != 0) - table = table_name_resolver_->resolve_pointer (m); - else - table = table_qname (imc, *imp); - } - - instance oc (table, sk_, sc_); - oc->traverse (imb, idt, "id", "object_id", &imc); - } - else - { - // Use the join alias instead of the actual table name unless we - // are handling a container. Generally, we want the join alias - // to be based on the column name. This is straightforward for - // single-column references. In case of a composite id, we will - // need to use the column prefix which is based on the data - // member name, unless overridden by the user. In the latter - // case the prefix can be empty, in which case we will just - // fall back on the member's public name. Note that the - // if(!table_name_.empty ()) test may look wrong at first but - // it is not; if table_name_ is empty then we are generating a - // container table where we don't qualify columns with tables. - // - string alias; - - if (!table_name_.empty ()) - { - if (table_name_resolver_ != 0) - alias = table_name_resolver_->resolve_pointer (m); - else - { - string n; - - if (composite_wrapper (idt)) - { - n = column_prefix (m, key_prefix_, default_name_).prefix; - - if (n.empty ()) - n = public_name_db (m); - else if (n[n.size () - 1] == '_') - n.resize (n.size () - 1); // Remove trailing underscore. - } - else - { - bool dummy; - n = column_name (m, key_prefix_, default_name_, dummy); - } - - alias = column_prefix_.prefix + n; - - if (poly) - { - qname const& table (table_name (imc)); - alias = quote_id (alias + "_" + table.uname ()); - } - else - alias = quote_id (alias); - } - } - - instance oc (alias, sk_, sc_); - oc->traverse (id); - } - } - else - object_columns_base::traverse_pointer (m, c); - } - - virtual bool - traverse_column (semantics::data_member& m, string const& name, bool) - { - // Ignore certain columns depending on what kind statement we are - // generating. Id and readonly columns are not present in the update - // statements. - // - if ((id () || readonly (member_path_, member_scope_)) && - sk_ == statement_update && ro_) - return false; - - return column (m, table_name_, quote_id (name)); - } - - virtual bool - column (semantics::data_member& m, - string const& table, - string const& column) - { - string r; - - if (!table.empty ()) - { - r += table; // Already quoted. - r += '.'; - } - - r += column; // Already quoted. - - string const& sqlt (column_type ()); - - // Version column (optimistic concurrency) requires special - // handling in the UPDATE statement. - // - // - if (sk_ == statement_update && version (m)) - { - r += "=" + r + "+1"; - } - else if (param_ != 0) - { - r += '='; - r += convert_to (param_->next (m, column, sqlt), sqlt, m); - } - else if (sk_ == statement_select) - r = convert_from (r, sqlt, m); - - sc_.push_back (statement_column (table, r, sqlt, m, key_prefix_)); - return true; - } - - protected: - statement_kind sk_; - bool ro_; - statement_columns& sc_; - query_parameters* param_; - string table_name_; - table_name_resolver* table_name_resolver_; - size_t depth_; - }; - - struct view_columns: object_columns_base, - object_columns::table_name_resolver, - virtual context - { - typedef view_columns base; - - view_columns (statement_columns& sc, - strings& from, - const view_relationship_map& rm) - : sc_ (sc), from_ (from), rel_map_ (rm), in_composite_ (false) {} - - // Implementation of table_name_resolver for object_columns. - // - virtual string - resolve_pointer (semantics::data_member& m) const - { - view_object& us (*ptr_->get ("view-object")); - - data_member_path& imp (*inverse (m)); - semantics::data_member& imf (*imp.front ()); - semantics::data_member& imb (*imp.back ()); - - using semantics::class_; - typedef view_relationship_map::const_iterator iterator; - - std::pair r (rel_map_.equal_range (imp)); - - for (; r.first != r.second; ++r.first) - { - if (r.first->second.second != &us) // Not our associated. - continue; - - view_object& vo (*r.first->second.first); // First because inverse. - - // Derive the table name the same way as the JOIN code. - // - class_* c (vo.obj); - if (class_* root = polymorphic (*c)) - { - // Can be in base. - // - c = &static_cast (imf.scope ()); - - if (!polymorphic (*c)) - c = root; - } - - string const& a (vo.alias); - - if (container (imb)) - { - // If this is a container, then object_columns will use the - // column from the container table, not from the object table - // (which, strictly speaking, might not have been JOIN'ed). - // - qname t (table_name (*c, imp)); - return a.empty () - ? quote_id (t) - : quote_id (a + '_' + t.uname ()); - } - else - { - qname t; - if (a.empty ()) - t = table_name (*c); - else - { - if (polymorphic (*c)) - t = qname (a + "_" + table_name (*c).uname ()); - else - t = qname (a); - } - return quote_id (t); - } - } - - // So there is no associated object for this column. The initial - // plan was to complain and ask the user to explicitly associate - // the object. This is not a bad plan except for one thing: if - // the direct side of the relationship is a container, then - // associating that object explicitly will result in both the - // container table and the object table being JOIN'ed. But we - // only need the container table (for the object id) So we will - // be joining a table for nothing, which is not very clean. So - // the alternative, and more difficult, plan is to go ahead and - // add the necessary JOIN's automatically. - // - // This code follows the normal JOIN generation code. - // - class_* o (object_pointer (utype (m))); - if (class_* root = polymorphic (*o)) - { - o = &static_cast (imf.scope ()); - - if (!polymorphic (*o)) - o = root; - } - - string const& a (us.alias); - string lt (a.empty () ? table_qname (*us.obj) : quote_id (a)); - string rt; - qname ct (container (imb) ? table_name (*o, imp) : table_name (*o)); - - string l ("LEFT JOIN "); - - if (a.empty ()) - { - rt = quote_id (ct); - l += rt; - } - else - { - // The same relationship can be used by multiple associated - // objects. So if we have an alias, then also construct one - // for the table that we are joining. - // - rt = quote_id (a + '_' + ct.uname ()); - l += quote_id (ct); - l += (need_alias_as ? " AS " : " ") + rt; - } - - l += " ON"; - from_.push_back (l); - - instance l_cols; // Our id columns. - instance r_cols; // Other side id columns. - - data_member_path& id (*id_member (*us.obj)); - - l_cols->traverse (id); - - if (container (imb)) - r_cols->traverse (imb, utype (id), "value", "value"); - else - r_cols->traverse (imb, column_prefix (imp)); - - for (object_columns_list::iterator b (l_cols->begin ()), i (b), - j (r_cols->begin ()); i != l_cols->end (); ++i, ++j) - { - l.clear (); - - if (i != b) - l += "AND "; - - l += lt; - l += '.'; - l += quote_id (i->name); - l += '='; - l += rt; - l += '.'; - l += quote_id (j->name); - - from_.push_back (strlit (l)); - } - - return rt; - - /* - // The alternative implementation: - // - location const& l1 (m.location ()); - location const& l2 (ptr_->location ()); - - string n1 (class_name (*object_pointer (utype (m)))); - string n2 (class_name (*object_pointer (utype (*ptr_)))); - - error (l1) << "object '" << n1 << "' pointed-to by the inverse " - << "data member in object '" << n2 << "' must be " - << "explicitly associated with the view" << endl; - - info (l2) << "view data member that loads '" << n2 << "' is " - << "defined here" << endl; - - throw operation_failed (); - */ - } - - virtual string - resolve_base (semantics::class_& b) const - { - view_object& vo (*ptr_->get ("view-object")); - - qname t (vo.alias.empty () - ? table_name (b) - : qname (vo.alias + "_" + table_name (b).uname ())); - - return quote_id (t); - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - type* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - size_t poly_depth (poly_derived ? polymorphic_depth (c) : 1); - - view_object& vo (*m.get ("view-object")); - string const& a (vo.alias); - - qname t; - if (a.empty ()) - t = table_name (c); - else - { - if (poly) - t = qname (a + "_" + table_name (c).uname ()); - else - t = qname (a); - } - string qt (quote_id (t)); - - ptr_ = &m; - - statement_kind sk (statement_select); // Imperfect forwarding. - object_section* s (&main_section); // Imperfect forwarding. - instance oc (qt, sk, sc_, poly_depth, s, this); - oc->traverse (c); - } - - virtual void - traverse_composite (semantics::data_member* pm, semantics::class_& c) - { - if (in_composite_) - { - object_columns_base::traverse_composite (pm, c); - return; - } - - // Override the column prerix. - // - semantics::data_member& m (*pm); - - // If we have literal column specified, use that. - // - if (m.count ("column")) - { - table_column const& tc (m.get ("column")); - - if (!tc.table.empty ()) - table_prefix_ = tc.table; - - column_prefix_ = object_columns_base::column_prefix (m); - } - // Otherwise, see if there is a column expression. For composite - // members in a view, this should be a single reference. - // - else if (m.count ("column-expr")) - { - column_expr const& e (m.get ("column-expr")); - - if (e.size () > 1) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: column expression specified for a data member " - << "of a composite value type" << endl; - - throw operation_failed (); - } - - data_member_path const& mp (e.back ().member_path); - - if (mp.size () > 1) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: invalid data member in db pragma column" - << endl; - - throw operation_failed (); - } - - table_prefix_ = e.back ().table; - column_prefix_ = object_columns_base::column_prefix (*mp.back ()); - } - else - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: no column prefix provided for a view data member" - << endl; - - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": info: use db pragma column to specify the column prefix" - << endl; - - throw operation_failed (); - } - - in_composite_ = true; - object_columns_base::traverse_composite (pm, c); - in_composite_ = false; - } - - virtual bool - traverse_column (semantics::data_member& m, string const& name, bool) - { - string tbl; - string col; - - // If we are inside a composite value, use the standard - // column name machinery. - // - if (in_composite_) - { - if (!table_prefix_.empty ()) - { - tbl = quote_id (table_prefix_); - col += tbl; - col += '.'; - } - - col += quote_id (name); - } - // If we have literal column specified, use that. - // - else if (m.count ("column")) - { - table_column const& tc (m.get ("column")); - - if (!tc.expr) - { - if (!tc.table.empty ()) - { - tbl = quote_id (tc.table); - col += tbl; - col += '.'; - } - - col += quote_id (tc.column); - } - else - col += tc.column; - } - // Otherwise, see if there is a column expression. - // - else if (m.count ("column-expr")) - { - column_expr const& e (m.get ("column-expr")); - - for (column_expr::const_iterator i (e.begin ()); i != e.end (); ++i) - { - switch (i->kind) - { - case column_expr_part::literal: - { - col += i->value; - break; - } - case column_expr_part::reference: - { - tbl = quote_id (i->table); - col += tbl; - col += '.'; - col += column_qname (i->member_path); - break; - } - } - } - } - else - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: no column name provided for a view data member" - << endl; - - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": info: use db pragma column to specify the column name" - << endl; - - throw operation_failed (); - } - - return column (m, tbl, col); - } - - // The column argument is a qualified and quoted column or - // expression. - // - virtual bool - column (semantics::data_member& m, - string const& table, - string const& column) - { - string const& sqlt (column_type ()); - sc_.push_back ( - statement_column ( - table, convert_from (column, sqlt, m), sqlt, m)); - return true; - } - - protected: - statement_columns& sc_; - strings& from_; - const view_relationship_map& rel_map_; - - bool in_composite_; - qname table_prefix_; // Table corresponding to column_prefix_; - - // Set to the current pointer data member that we are traversing. - // - semantics::data_member* ptr_; - }; - - struct polymorphic_object_joins: object_columns_base, virtual context - { - typedef polymorphic_object_joins base; - - polymorphic_object_joins (semantics::class_& obj, - bool query, - size_t depth, - string const& alias = "", - user_section* section = 0) - : object_columns_base (true, true), - obj_ (obj), - query_ (query), - depth_ (depth), - section_ (section), - alias_ (alias) - { - // Get the table and id columns. - // - table_ = alias_.empty () - ? table_qname (obj_) - : quote_id (alias_ + "_" + table_name (obj_).uname ()); - - cols_->traverse (*id_member (obj_)); - } - - virtual void - traverse_object (semantics::class_& c) - { - // If section is specified, skip bases that don't add anything - // to load. - // - bool skip (false), stop (false); - if (section_ != 0) - { - skip = true; - - if (section_->object == &c) - { - user_section& s (*section_); - - if (s.total != 0 || s.optimistic ()) - skip = false; - - section_ = s.base; // Move to the next base. - - if (section_ == 0) - stop = true; // Stop at this base if there are no more overrides. - } - } - // Skip intermediates that don't add any data members. - // - else if (!query_) - { - column_count_type const& cc (column_count (c)); - if (cc.total == cc.id + cc.separate_load) - skip = true; - } - - if (!skip) - { - std::ostringstream cond; - - qname table (table_name (c)); - string alias (alias_.empty () - ? quote_id (table) - : quote_id (alias_ + "_" + table.uname ())); - - for (object_columns_list::iterator b (cols_->begin ()), i (b); - i != cols_->end (); - ++i) - { - if (i != b) - cond << " AND "; - - string qn (quote_id (i->name)); - cond << alias << '.' << qn << '=' << table_ << '.' << qn; - } - - string line ("LEFT JOIN " + quote_id (table)); - - if (!alias_.empty ()) - line += (need_alias_as ? " AS " : " ") + alias; - - line += " ON " + cond.str (); - - joins.push_back (line); - } - - if (!stop && --depth_ != 0) - inherits (c); - } - - public: - strings joins; - - strings::const_iterator - begin () const {return joins.begin ();} - - strings::const_iterator - end () const {return joins.end ();} - - private: - semantics::class_& obj_; - bool query_; - size_t depth_; - user_section* section_; - string alias_; - string table_; - instance cols_; - }; - - struct object_joins: object_columns_base, virtual context - { - typedef object_joins base; - - //@@ context::{cur,top}_object; might have to be created every time. - // - object_joins (semantics::class_& scope, - bool query, - size_t depth, - object_section* section = 0) - : object_columns_base (true, true, section), - query_ (query), - depth_ (depth), - table_ (table_qname (scope)), - id_ (*id_member (scope)) - { - id_cols_->traverse (id_); - } - - virtual bool - section_test (data_member_path const& mp) - { - object_section& s (section (mp)); - - // Include eager loaded members into the main section. - // - return section_ == 0 || - *section_ == s || - (*section_ == main_section && !s.separate_load ()); - } - - virtual void - traverse_object (semantics::class_& c) - { - // If this is a derived type in a polymorphic hierarchy, then we - // need to include base joins, but do it in reverse order as well - // as switch the table name (base columns come from different - // tables). - // - semantics::class_* poly_root (polymorphic (c)); - if (poly_root != 0 && poly_root != &c) - { - names (c); - - if (query_ || --depth_ != 0) - { - table_ = table_qname (polymorphic_base (c)); - inherits (c); - } - } - else - object_columns_base::traverse_object (c); - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - // Ignore polymorphic id references; they are joined by - // polymorphic_object_joins in a special way. - // - if (m.count ("polymorphic-ref")) - return; - - string t, a, dt, da; - std::ostringstream cond, dcond; // @@ diversion? - - // Derive table alias for this member. Generally, we want the - // alias to be based on the column name. This is straightforward - // for single-column references. In case of a composite id, we - // will need to use the column prefix which is based on the data - // member name, unless overridden by the user. In the latter - // case the prefix can be empty, in which case we will just - // fall back on the member's public name. - // - string alias; - { - string n; - - if (composite_wrapper (utype (*id_member (c)))) - { - n = column_prefix (m, key_prefix_, default_name_).prefix; - - if (n.empty ()) - n = public_name_db (m); - else if (n[n.size () - 1] == '_') - n.resize (n.size () - 1); // Remove trailing underscore. - } - else - { - bool dummy; - n = column_name (m, key_prefix_, default_name_, dummy); - } - - alias = column_prefix_.prefix + n; - } - - semantics::class_* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - - semantics::class_* joined_obj (0); - - if (data_member_path* imp = inverse (m, key_prefix_)) - { - semantics::data_member& imf (*imp->front ()); - semantics::data_member& imb (*imp->back ()); - - // In a polymorphic hierarchy the inverse member can be in - // the base class, in which case we should use that table. - // - semantics::class_& imc ( - poly ? dynamic_cast (imf.scope ()) : c); - - if (container (imb)) - { - // This container is a direct member of the class so the table - // prefix is just the class table name. - // - t = table_qname (imc, *imp); - - // Container's value is our id. - // - instance id_cols; - id_cols->traverse (imb, utype (id_), "value", "value"); - - for (object_columns_list::iterator b (id_cols->begin ()), i (b), - j (id_cols_->begin ()); i != id_cols->end (); ++i, ++j) - { - - if (i != b) - cond << " AND "; - - cond << t << '.' << quote_id (i->name) << '=' << - table_ << '.' << quote_id (j->name); - } - - // Add the join for the object itself so that we are able to - // use it in the WHERE clause. - // - if (query_) - { - // Here we can use the most derived class instead of the - // one containing the inverse member. - // - qname const& table (table_name (c)); - - dt = quote_id (table); - da = quote_id (poly ? alias + "_" + table.uname () : alias); - - data_member_path& id (*id_member (c)); - - instance oid_cols, cid_cols; - oid_cols->traverse (id); - cid_cols->traverse (imb, utype (id), "id", "object_id", &c); - - for (object_columns_list::iterator b (cid_cols->begin ()), i (b), - j (oid_cols->begin ()); i != cid_cols->end (); ++i, ++j) - { - - if (i != b) - dcond << " AND "; - - dcond << da << '.' << quote_id (j->name) << '=' << - t << '.' << quote_id (i->name); - } - - joined_obj = &c; - } - } - else - { - qname const& table (table_name (imc)); - - t = quote_id (table); - a = quote_id (poly ? alias + "_" + table.uname () : alias); - - instance id_cols; - id_cols->traverse (imb, column_prefix (*imp)); - - for (object_columns_list::iterator b (id_cols->begin ()), i (b), - j (id_cols_->begin ()); i != id_cols->end (); ++i, ++j) - { - if (i != b) - cond << " AND "; - - cond << a << '.' << quote_id (i->name) << '=' << - table_ << '.' << quote_id (j->name); - } - - // If we are generating query, JOIN base/derived classes so - // that we can use their data in the WHERE clause. - // - if (query_) - joined_obj = &imc; - } - } - else if (query_) - { - // We need the join to be able to use the referenced object - // in the WHERE clause. - // - qname const& table (table_name (c)); - - t = quote_id (table); - a = quote_id (poly ? alias + "_" + table.uname () : alias); - - instance oid_cols (column_prefix_); - oid_cols->traverse (m); - - instance pid_cols; - pid_cols->traverse (*id_member (c)); - - for (object_columns_list::iterator b (pid_cols->begin ()), i (b), - j (oid_cols->begin ()); i != pid_cols->end (); ++i, ++j) - { - - if (i != b) - cond << " AND "; - - cond << a << '.' << quote_id (i->name) << '=' << - table_ << '.' << quote_id (j->name); - } - - joined_obj = &c; - } - - if (!t.empty ()) - { - string line ("LEFT JOIN "); - line += t; - - if (!a.empty ()) - line += (need_alias_as ? " AS " : " ") + a; - - line += " ON "; - line += cond.str (); - - joins.push_back (line); - } - - // Add dependent join (i.e., an object table join via the - // container table). - // - if (!dt.empty ()) - { - string line ("LEFT JOIN "); - line += dt; - - if (!da.empty ()) - line += (need_alias_as ? " AS " : " ") + da; - - line += " ON "; - line += dcond.str (); - - joins.push_back (line); - } - - // If we joined the object that is part of a polymorphic type - // hierarchy, then we may need join its bases as well as its - // derived types. This is only done for queries. - // - if (joined_obj != 0 && poly) - { - size_t depth (polymorphic_depth (*joined_obj)); - - // Join "up" (derived). - // - if (joined_obj != &c) - { - bool t (true); //@@ (im)perfect forward. - size_t d (polymorphic_depth (c) - depth); //@@ (im)perfect forward. - instance j (*joined_obj, t, d, alias); - j->traverse (c); - joins.insert (joins.end (), j->joins.begin (), j->joins.end ()); - } - - // Join "down" (base). - // - if (joined_obj != poly_root) - { - bool t (true); //@@ (im)perfect forward. - size_t d (depth - 1); //@@ (im)perfect forward. - instance j (*joined_obj, t, d, alias); - j->traverse (polymorphic_base (*joined_obj)); - joins.insert (joins.end (), j->joins.begin (), j->joins.end ()); - } - } - } - - public: - strings joins; - - strings::const_iterator - begin () const {return joins.begin ();} - - strings::const_iterator - end () const {return joins.end ();} - - private: - bool query_; - size_t depth_; - string table_; - data_member_path& id_; - instance id_cols_; - }; - - // Check that eager object pointers in the objects that a view loads - // can be loaded from the cache (i.e., they have session support - // enabled). - // - struct view_object_check: object_members_base - { - typedef view_object_check base; - - view_object_check (view_object& vo, view_relationship_map& rm) - : object_members_base (false, &main_section), - session_ (false), vo_ (vo), rel_map_ (rm) {} - - virtual bool - section_test (data_member_path const& mp) - { - // Include eager loaded members into the main section. - // - object_section& s (section (mp)); - return *section_ == s || !s.separate_load (); - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - // Ignore polymorphic id references. - // - if (m.count ("polymorphic-ref")) - return; - - check (m, inverse (m), utype (m), c); - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type&) - { - semantics::type& vt (container_vt (m)); - - if (semantics::class_* cvt = composite_wrapper (vt)) - { - // Check this composite value for any pointers. - // - instance t (vo_, rel_map_); - t->traverse (*cvt); - - session_ = session_ || t->session_; - } - else if (semantics::class_* c = object_pointer (vt)) - check (m, inverse (m, "value"), vt, *c); - } - - void - check (semantics::data_member& m, - data_member_path* imp, - semantics::type& pt, // Pointer type. - semantics::class_& c) - { - // We don't care about lazy pointers. - // - if (lazy_pointer (pt)) - return; - - // First check the pointed-to object recursively. - // - if (!c.count ("view-object-check-seen")) - { - c.set ("view-object-check-seen", true); - instance t (vo_, rel_map_); - t->traverse (c); - - // We may come again for another view. - // - c.remove ("view-object-check-seen"); - - session_ = session_ || t->session_; - } - - // See if the pointed-to object in this relationship is loaded - // by this view. - // - typedef view_relationship_map::const_iterator iterator; - - std::pair r ( - rel_map_.equal_range (imp != 0 ? *imp : member_path_)); - - if (r.first == r.second) - return; // This relationship does not figure in the view. - - view_object& vo (*(imp != 0 - ? r.first->second.first - : r.first->second.second)); - - assert (vo.obj == &c); // Got the above right? - - if (vo.ptr == 0) - return; // This object is not loaded by the view. - - // The pointed-to object in this relationship is loaded - // by the view. The hard question, of course, is whether - // it has anything to do with us. We assume it does. - // - if (!session (c)) - { - // Always direct data member. - // - semantics::class_& v ( - dynamic_cast (vo.ptr->scope ())); - - location const& l1 (c.location ()); - location const& l2 (m.location ()); - location const& l3 (vo_.ptr->location ()); - location const& l4 (vo.ptr->location ()); - - string on (class_name (c)); - string vn (class_name (v)); - - error (l1) << "object '" << on << "' has session support disabled " - << "but may be loaded by view '" << vn << "' via " - << "several data members" << endl; - - info (l2) << "indirectly via this data member..." << endl; - info (l3) << "...as a result of this object load" << endl; - info (l4) << "and directly as a result of this load" << endl; - info (l1) << "session support is required to only load one copy " - << "of the object" << endl; - info (l1) << "and don't forget to create a session instance when " - << "using this view" << endl; - - throw operation_failed (); - } - - session_ = true; - } - - bool session_; - - private: - view_object& vo_; - view_relationship_map& rel_map_; - }; - - // - // bind - // - - struct bind_member: virtual member_base - { - typedef bind_member base; - - // NULL section means we are generating object bind(). - // - bind_member (string const& var = string (), - string const& arg = string (), - object_section* section = 0) - : member_base (var, 0, 0, string (), string (), section), - arg_override_ (arg) {} - - bind_member (string const& var, - string const& arg, - semantics::type& t, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base (var, &t, ct, fq_type, key_prefix), - arg_override_ (arg) {} - - protected: - string arg_override_; - }; - - template - struct bind_member_impl: bind_member, virtual member_base_impl - { - typedef bind_member_impl base_impl; - - bind_member_impl (base const& x): base (x) {} - - typedef typename member_base_impl::member_info member_info; - - using member_base_impl::container; - - virtual bool - pre (member_info& mi) - { - if (container (mi)) - return false; - - // Treat version as present in every section. - // - if (section_ != 0 && !version (mi.m) && *section_ != section (mi.m)) - return false; - - // Ignore polymorphic id references; they are bound in a special - // way. - // - if (mi.ptr != 0 && mi.m.count ("polymorphic-ref")) - return false; - - std::ostringstream ostr; - ostr << "b[n]"; - b = ostr.str (); - - arg = arg_override_.empty () ? string ("i") : arg_override_; - - if (var_override_.empty ()) - { - // Ignore inverse, separately-loaded members in the main - // section (nothing to persist). - // - if (section_ == 0 && separate_load (mi.m) && inverse (mi.m)) - return false; - - semantics::class_* comp (composite (mi.t)); - - os << "// " << mi.m.name () << endl - << "//" << endl; - - // Order of these tests is important. - // - if (!insert_send_auto_id && auto_ (mi.m)) - os << "if (sk != statement_insert && sk != statement_update)" - << "{"; - else if (section_ == 0 && separate_load (mi.m)) - os << "if (sk == statement_insert)" - << "{"; - else if (inverse (mi.m, key_prefix_) || version (mi.m)) - os << "if (sk == statement_select)" - << "{"; - // If the whole class is readonly, then we will never be - // called with sk == statement_update. - // - else if (!readonly (*context::top_object)) - { - if (id (mi.m) || - readonly (mi.m) || - (comp != 0 && readonly (*comp)) || - (section_ == 0 && separate_update (mi.m))) - os << "if (sk != statement_update)" - << "{"; - } - - // 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 this is a composite member, see if it is summarily - // added/deleted. - // - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - // If the addition/deletion version is the same as the section's, - // then we don't need the test. - // - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - 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 << ")" - << "{"; - } - } - - return true; - } - - virtual void - post (member_info& mi) - { - if (var_override_.empty ()) - { - semantics::class_* comp (composite (mi.t)); - - // We need to increment the index even if we skipped this - // member due to the schema version. - // - unsigned long long av (added (mi.m)); - unsigned long long dv (deleted (mi.m)); - - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if (av != 0 || dv != 0) - os << "}"; - - if (mi.ptr != 0 && view_member (mi.m)) - { - // See column_count_impl for details on what's going on here. - // - column_count_type cc; - if (semantics::class_* root = polymorphic (*mi.ptr)) - { - for (semantics::class_* b (mi.ptr);; b = &polymorphic_base (*b)) - { - column_count_type const& ccb (column_count (*b)); - - cc.total += ccb.total - (b != root ? ccb.id : 0); - cc.separate_load += ccb.separate_load; - - if (b == root) - break; - } - } - else - cc = column_count (*mi.ptr); - - os << "n += " << cc.total - cc.separate_load << "UL;"; - } - else if (comp != 0) - { - bool ro (readonly (*comp)); - column_count_type const& cc (column_count (*comp)); - - os << "n += " << cc.total << "UL"; - - // select = total - // insert = total - inverse - // update = total - inverse - readonly - // - if (cc.inverse != 0 || (!ro && cc.readonly != 0)) - { - os << " - (" << endl - << "sk == statement_select ? 0 : "; - - if (cc.inverse != 0) - os << cc.inverse << "UL"; - - if (!ro && cc.readonly != 0) - { - if (cc.inverse != 0) - os << " + "; - - os << "(" << endl - << "sk == statement_insert ? 0 : " << - cc.readonly << "UL)"; - } - - os << ")"; - } - - os << ";"; - } - else - os << "n++;"; - - bool block (false); - - // The same logic as in pre(). - // - if (!insert_send_auto_id && auto_ (mi.m)) - block = true; - else if (section_ == 0 && separate_load (mi.m)) - block = true; - else if (inverse (mi.m, key_prefix_) || version (mi.m)) - block = true; - else if (!readonly (*context::top_object)) - { - semantics::class_* c; - - if (id (mi.m) || - readonly (mi.m) || - ((c = composite (mi.t)) && readonly (*c)) || - (section_ == 0 && separate_update (mi.m))) - block = true; - } - - if (block) - os << "}"; - else - os << endl; - } - } - - virtual void - traverse_pointer (member_info& mi) - { - // Object pointers in views require special treatment. - // - if (view_member (mi.m)) - { - semantics::class_& c (*mi.ptr); - semantics::class_* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - - os << "object_traits_impl< " << class_fq_name (c) << ", id_" << - db << " >::bind (" << endl - << "b + n, " << (poly_derived ? "0, 0, " : "") << arg << "." << - mi.var << "value, sk" << (versioned (c) ? ", svm" : "") << ");"; - } - else - member_base_impl::traverse_pointer (mi); - } - - virtual void - traverse_composite (member_info& mi) - { - os << "composite_value_traits< " << mi.fq_type () << ", id_" << - db << " >::bind (" << endl - << "b + n, " << arg << "." << mi.var << "value, sk" << - (versioned (*composite (mi.t)) ? ", svm" : "") << ");"; - } - - protected: - string b; - string arg; - }; - - struct bind_base: traversal::class_, virtual context - { - typedef bind_base base; - - virtual void - traverse (type& c) - { - bool obj (object (c)); - - // Ignore transient bases. Not used for views. - // - if (!(obj || composite (c))) - return; - - os << "// " << class_name (c) << " base" << endl - << "//" << endl; - - // If the derived class is readonly, then we will never be - // called with sk == statement_update. - // - bool ro (readonly (c)); - bool check (ro && !readonly (*context::top_object)); - - if (check) - os << "if (sk != statement_update)" - << "{"; - - if (obj) - os << "object_traits_impl< "; - else - os << "composite_value_traits< "; - - os << class_fq_name (c) << ", id_" << db << " >::bind (b + n, i, sk" << - (versioned (c) ? ", svm" : "") << ");"; - - column_count_type const& cc (column_count (c)); - - os << "n += "; - - // select = total - separate_load - // insert = total - inverse - optimistic_managed - id(auto & !sending) - // update = total - inverse - optimistic_managed - id - readonly - - // separate_update - // - size_t select (cc.total - cc.separate_load); - size_t insert (cc.total - cc.inverse - cc.optimistic_managed); - size_t update (insert - cc.id - cc.readonly - cc.separate_update); - - data_member_path* id; - if (!insert_send_auto_id && (id = id_member (c)) != 0 && auto_ (*id)) - insert -= cc.id; - - if (select == insert && insert == update) - os << select << "UL;"; - else if (select != insert && insert == update) - os << "sk == statement_select ? " << select << "UL : " << - insert << "UL;"; - else if (select == insert && insert != update) - os << "sk == statement_update ? " << update << "UL : " << - select << "UL;"; - else - os << "sk == statement_select ? " << select << "UL : " << - "sk == statement_insert ? " << insert << "UL : " << - update << "UL;"; - - if (check) - os << "}"; - else - os << endl; - } - }; - - // - // grow - // - - struct grow_member: virtual member_base - { - typedef grow_member base; - - grow_member (size_t& index, - string const& var = string (), - user_section* section = 0) - : member_base (var, 0, 0, string (), string (), section), - index_ (index) {} - - grow_member (size_t& index, - string const& var, - semantics::type& t, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base (var, &t, ct, fq_type, key_prefix), index_ (index) {} - - protected: - size_t& index_; - }; - - template - struct grow_member_impl: grow_member, virtual member_base_impl - { - typedef grow_member_impl base_impl; - - grow_member_impl (base const& x) - : member_base::base (x), // virtual base - base (x) {} - - typedef typename member_base_impl::member_info member_info; - - using member_base_impl::container; - - virtual bool - pre (member_info& mi) - { - if (container (mi)) - return false; - - // If we have a key prefix (container), then it can't be in a section - // (while mi.m can). The same for top-level -- if we got called, then - // we shouldn't ignore it. (Same logic as in has_grow_member). - // - if (!(!key_prefix_.empty () || top_level_ || - (section_ == 0 && !separate_load (mi.m)) || - (section_ != 0 && *section_ == section (mi.m)))) - return false; - - // Ignore polymorphic id references; they are not returned by - // the select statement. - // - if (mi.ptr != 0 && mi.m.count ("polymorphic-ref")) - return false; - - std::ostringstream ostr; - ostr << "t[" << index_ << "UL]"; - e = ostr.str (); - - if (var_override_.empty ()) - { - os << "// " << mi.m.name () << endl - << "//" << endl; - - semantics::class_* comp (composite (mi.t)); - - // 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 this is a composite member, see if it is summarily - // added/deleted. - // - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - // If the addition/deletion version is the same as the section's, - // then we don't need the test. - // - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - 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 << ")" - << "{"; - } - } - - return true; - } - - virtual void - post (member_info& mi) - { - semantics::class_* comp (composite (mi.t)); - - if (var_override_.empty ()) - { - unsigned long long av (added (mi.m)); - unsigned long long dv (deleted (mi.m)); - - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if (av != 0 || dv != 0) - os << "}"; - } - - if (mi.ptr != 0 && view_member (mi.m)) - { - // See column_count_impl for details on what's going on here. - // - column_count_type cc; - if (semantics::class_* root = polymorphic (*mi.ptr)) - { - for (semantics::class_* b (mi.ptr);; b = &polymorphic_base (*b)) - { - column_count_type const& ccb (column_count (*b)); - - cc.total += ccb.total - (b != root ? ccb.id : 0); - cc.separate_load += ccb.separate_load; - - if (b == root) - break; - } - } - else - cc = column_count (*mi.ptr); - - index_ += cc.total - cc.separate_load; - } - else if (comp != 0) - index_ += column_count (*comp).total; - else - index_++; - } - - virtual void - traverse_pointer (member_info& mi) - { - // Object pointers in views require special treatment. They - // can only be immediate members of the view class. - // - if (view_member (mi.m)) - { - semantics::class_& c (*mi.ptr); - - os << "if (object_traits_impl< " << class_fq_name (c) << - ", id_" << db << " >::grow (" << endl - << "i." << mi.var << "value, t + " << index_ << "UL" << - (versioned (c) ? ", svm" : "") << "))" << endl - << "grew = true;" - << endl; - } - else - member_base_impl::traverse_pointer (mi); - } - - virtual void - traverse_composite (member_info& mi) - { - semantics::class_& c (*composite (mi.t)); - - os << "if (composite_value_traits< " << mi.fq_type () << - ", id_" << db << " >::grow (" << endl - << "i." << mi.var << "value, t + " << index_ << "UL" << - (versioned (c) ? ", svm" : "") << "))" << endl - << "grew = true;" - << endl; - } - - protected: - string e; - }; - - struct grow_base: traversal::class_, virtual context - { - typedef grow_base base; - - grow_base (size_t& index): index_ (index) {} - - virtual void - traverse (type& c) - { - bool obj (object (c)); - - // Ignore transient bases. Not used for views. - // - if (!(obj || composite (c))) - return; - - os << "// " << class_name (c) << " base" << endl - << "//" << endl; - - os << "if ("; - - if (obj) - os << "object_traits_impl< "; - else - os << "composite_value_traits< "; - - os << class_fq_name (c) << ", id_" << db << " >::grow (" << endl - << "i, t + " << index_ << "UL" << - (versioned (c) ? ", svm" : "") << "))" << endl - << "grew = true;" - << endl; - - index_ += column_count (c).total; - } - - protected: - size_t& index_; - }; - - // - // init image - // - - struct init_image_member: virtual member_base - { - typedef init_image_member base; - - init_image_member (string const& var = string (), - string const& member = string (), - user_section* section = 0) - : member_base (var, 0, 0, string (), string (), section), - member_override_ (member) - { - } - - init_image_member (string const& var, - string const& member, - semantics::type& t, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base (var, &t, ct, fq_type, key_prefix), - member_override_ (member) - { - } - - protected: - string member_override_; - }; - - template - struct init_image_member_impl: init_image_member, - virtual member_base_impl - { - typedef init_image_member_impl base_impl; - - init_image_member_impl (base const& x) - : base (x), - member_database_type_id_ (base::type_override_, - base::custom_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - typedef typename member_base_impl::member_info member_info; - - using member_base_impl::container; - - virtual void - set_null (member_info&) = 0; - - virtual void - check_accessor (member_info&, member_access&) {} - - virtual bool - pre (member_info& mi) - { - // Ignore containers (they get their own table) and inverse - // object pointers (they are not present in this binding). - // - if (container (mi) || inverse (mi.m, key_prefix_)) - return false; - - if (section_ != 0 && *section_ != section (mi.m)) - return false; - - // Ignore polymorphic id references; they are initialized in a - // special way. - // - if (mi.ptr != 0 && mi.m.count ("polymorphic-ref")) - return false; - - semantics::class_* comp (composite (mi.t)); - - if (!member_override_.empty ()) - { - member = member_override_; - os << "{"; - } - else - { - // If we are generating standard init() and this member - // contains version, ignore it. - // - if (version (mi.m)) - return false; - - // If we don't send auto id in INSERT statement, ignore this - // member altogether (we never send auto id in UPDATE). - // - if (!insert_send_auto_id && auto_ (mi.m)) - return false; - - os << "// " << mi.m.name () << endl - << "//" << endl; - - // 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 this is a composite member, see if it is summarily - // added/deleted. - // - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - // If the addition/deletion version is the same as the section's, - // then we don't need the test. - // - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - 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 class is readonly, then we will never be - // called with sk == statement_update. - // - if (!readonly (*context::top_object)) - { - if (id (mi.m) || - readonly (mi.m) || - (section_ == 0 && separate_update (mi.m)) || - (comp != 0 && readonly (*comp))) // Can't be id. - { - // If we are generating section init(), then sk can only be - // statement_update. - // - if (section_ == 0) - os << "if (sk == statement_insert)"; - } - } - - os << "{"; - - if (discriminator (mi.m)) - member = "di.discriminator"; - else - { - // Get the member using the accessor expression. - // - member_access& ma (mi.m.template get ("get")); - - // Make sure this kind of member can be accessed with this - // kind of accessor (database-specific, e.g., streaming). - // - if (comp == 0) - check_accessor (mi, ma); - - // If this is not a synthesized expression, then output - // its location for easier error tracking. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - // Use the original type to form the const reference. VC++ - // cannot grok the constructor syntax. - // - os << member_ref_type (mi.m, true, "v") << " =" << endl - << " " << ma.translate ("o") << ";" - << endl; - - member = "v"; - } - } - - // Translate. - // - if (mi.ct != 0) - { - os << "// From " << location_string (mi.ct->loc, true) << endl - << type_ref_type (*mi.ct->as, mi.ct->as_hint, true, "vt") << - " =" << endl - << " " << mi.ct->translate_to (member) << ";" - << endl; - - member = "vt"; - } - - // If this is a wrapped composite value, then we need to "unwrap" - // it. If this is a NULL wrapper, then we also need to handle that. - // For simple values this is taken care of by the value_traits - // specializations. - // - if (mi.wrapper != 0 && comp != 0) - { - // The wrapper type, not the wrapped type. - // - string const& wt (mi.fq_type (false)); - - // If this is a NULL wrapper and the member can be NULL, then - // we need to handle the NULL value. - // - if (null (mi.m, key_prefix_) && - mi.wrapper->template get ("wrapper-null-handler")) - { - os << "if (wrapper_traits< " << wt << " >::get_null (" << - member << "))" << endl - << "composite_value_traits< " << mi.fq_type () << ", id_" << - db << " >::set_null (" << endl - << "i." << mi.var << "value, sk" << - (versioned (*comp) ? ", svm" : "") << ");" - << "else" - << "{"; - } - - os << "const" << mi.fq_type () << "& vw = " << endl - << " wrapper_traits< " + wt + " >::get_ref (" + member + ");" - << endl; - - member = "vw"; - } - - if (discriminator (mi.m)) - os << "const info_type& di (map->find (typeid (o)));" - << endl; - - if (mi.ptr != 0) - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& pt (utype (mi.m, key_prefix_)); - - type = "obj_traits::id_type"; - - // Handle NULL pointers and extract the id. - // - os << "typedef object_traits< " << class_fq_name (*mi.ptr) << - " > obj_traits;"; - - if (weak_pointer (pt)) - { - os << "typedef odb::pointer_traits< " << mi.ptr_fq_type () << - " > wptr_traits;" - << "typedef odb::pointer_traits< wptr_traits::" << - "strong_pointer_type > ptr_traits;" - << endl - << "wptr_traits::strong_pointer_type sp (" << - "wptr_traits::lock (" << member << "));"; - - member = "sp"; - } - else - os << "typedef odb::pointer_traits< " << mi.ptr_fq_type () << - " > ptr_traits;" - << endl; - - os << "bool is_null (ptr_traits::null_ptr (" << member << "));" - << "if (!is_null)" - << "{" - << "const " << type << "& ptr_id (" << endl; - - if (lazy_pointer (pt)) - os << "ptr_traits::object_id< ptr_traits::element_type > (" << - member << ")"; - else - os << "obj_traits::id (ptr_traits::get_ref (" << member << "))"; - - os << ");" - << endl; - - member = "ptr_id"; - } - else if (comp != 0) - type = mi.fq_type (); - else - { - type = mi.fq_type (); - - // Indicate to the value_traits whether this column can be NULL. - // - os << "bool is_null (" << null (mi.m, key_prefix_) << ");"; - } - - if (comp != 0) - traits = "composite_value_traits< " + type + ", id_" + - db.string () + " >"; - else - { - db_type_id = member_database_type_id_->database_type_id (mi.m); - traits = db.string () + "::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - - virtual void - post (member_info& mi) - { - semantics::class_* comp (composite (mi.t)); - - if (mi.ptr != 0) - { - os << "}" - << "else" << endl; - - if (!null (mi.m, key_prefix_)) - os << "throw null_pointer ();"; - else if (comp != 0) - os << traits << "::set_null (i." << mi.var << "value, sk" << - (versioned (*comp) ? ", svm" : "") << ");"; - else - set_null (mi); - } - - if (mi.wrapper != 0 && comp != 0) - { - if (null (mi.m, key_prefix_) && - mi.wrapper->template get ("wrapper-null-handler")) - os << "}"; - } - - os << "}"; - - if (member_override_.empty ()) - { - unsigned long long av (added (mi.m)); - unsigned long long dv (deleted (mi.m)); - - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if (av != 0 || dv != 0) - os << "}"; - } - } - - virtual void - traverse_composite (member_info& mi) - { - bool grow (generate_grow && - context::grow (mi.m, mi.t, mi.ct, key_prefix_)); - - if (grow) - os << "if ("; - - os << traits << "::init (" << endl - << "i." << mi.var << "value," << endl - << member << "," << endl - << "sk"; - - if (versioned (*composite (mi.t))) - os << "," << endl - << "svm"; - - os << ")"; - - if (grow) - os << ")" << endl - << "grew = true"; - - os << ";"; - } - - protected: - string type; - string db_type_id; - string member; - string traits; - - instance member_database_type_id_; - }; - - struct init_image_base: traversal::class_, virtual context - { - typedef init_image_base base; - - virtual void - traverse (type& c) - { - bool obj (object (c)); - - // Ignore transient bases. Not used for views. - // - if (!(obj || composite (c))) - return; - - os << "// " << class_name (c) << " base" << endl - << "//" << endl; - - // If the derived class is readonly, then we will never be - // called with sk == statement_update. - // - bool check (readonly (c) && !readonly (*context::top_object)); - - if (check) - os << "if (sk != statement_update)" - << "{"; - - if (generate_grow) - os << "if ("; - - if (obj) - os << "object_traits_impl< "; - else - os << "composite_value_traits< "; - - os << class_fq_name (c) << ", id_" << db << " >::init (i, o, sk" << - (versioned (c) ? ", svm" : "") << ")"; - - if (generate_grow) - os << ")" << endl - << "grew = true"; - - os << ";"; - - if (check) - os << "}"; - else - os << endl; - } - }; - - // - // init value - // - - struct init_value_member: virtual member_base - { - typedef init_value_member base; - - init_value_member (string const& member = string (), - string const& var = string (), - bool ignore_implicit_discriminator = true, - user_section* section = 0) - : member_base (var, 0, 0, string (), string (), section), - member_override_ (member), - ignore_implicit_discriminator_ (ignore_implicit_discriminator) - { - } - - init_value_member (string const& var, - string const& member, - semantics::type& t, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base (var, &t, ct, fq_type, key_prefix), - member_override_ (member), - ignore_implicit_discriminator_ (true) - { - } - - virtual void - get_null (string const& /*var*/) const {}; - - protected: - string member_override_; - bool ignore_implicit_discriminator_; - }; - - template - struct init_value_member_impl: init_value_member, - virtual member_base_impl - { - typedef init_value_member_impl base_impl; - - init_value_member_impl (base const& x) - : base (x), - member_database_type_id_ (base::type_override_, - base::custom_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - typedef typename member_base_impl::member_info member_info; - - using member_base_impl::container; - - virtual void - get_null (string const& var) const = 0; - - virtual void - check_modifier (member_info&, member_access&) {} - - virtual bool - pre (member_info& mi) - { - if (container (mi)) - return false; - - if (section_ != 0 && *section_ != section (mi.m)) - return false; - - // Ignore polymorphic id references; they are initialized in a - // special way. - // - if (mi.ptr != 0 && mi.m.count ("polymorphic-ref")) - return false; - - // Ignore implicit discriminators. - // - if (ignore_implicit_discriminator_ && discriminator (mi.m)) - return false; - - semantics::class_* comp (composite (mi.t)); - - if (!member_override_.empty ()) - { - os << "{"; - member = member_override_; - } - else - { - // Ignore separately loaded members. - // - if (section_ == 0 && separate_load (mi.m)) - return false; - - os << "// " << mi.m.name () << endl - << "//" << endl; - - // 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 this is a composite member, see if it is summarily - // added/deleted. - // - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - // If the addition/deletion version is the same as the section's, - // then we don't need the test. - // - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - 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 << ")"; - } - - os << "{"; - - if (mi.ptr != 0 && view_member (mi.m)) - return true; // That's enough for the object pointer in view. - - // Set the member using the modifier expression. - // - member_access& ma (mi.m.template get ("set")); - - // Make sure this kind of member can be modified with this - // kind of accessor (database-specific, e.g., streaming). - // - if (comp == 0) - check_modifier (mi, ma); - - // If this is not a synthesized expression, then output - // its location for easier error tracking. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - // See if we are modifying via a reference or proper modifier. - // - if (ma.placeholder ()) - os << member_val_type (mi.m, false, "v") << ";" - << endl; - else - { - // Use the original type to form the reference. VC++ cannot - // grok the constructor syntax. - // - os << member_ref_type (mi.m, false, "v") << " =" << endl - << " "; - - // If this member is const and we have a synthesized direct - // access, then cast away constness. Otherwise, we assume - // that the user-provided expression handles this. - // - bool cast (mi.cq && ma.direct ()); - if (cast) - os << "const_cast< " << member_ref_type (mi.m, false) << - " > (" << endl; - - os << ma.translate ("o"); - - if (cast) - os << ")"; - - os << ";" - << endl; - } - - member = "v"; - } - - // Translate. - // - if (mi.ct != 0) - { - os << type_val_type (*mi.ct->as, mi.ct->as_hint, false, "vt") << ";" - << endl; - - translate_member = member; - member = "vt"; - } - - // If this is a wrapped composite value, then we need to "unwrap" it. - // If this is a NULL wrapper, then we also need to handle that. For - // simple values this is taken care of by the value_traits - // specializations. - // - if (mi.wrapper != 0 && comp != 0) - { - // The wrapper type, not the wrapped type. - // - string const& wt (mi.fq_type (false)); - - // If this is a NULL wrapper and the member can be NULL, then - // we need to handle the NULL value. - // - if (null (mi.m, key_prefix_) && - mi.wrapper->template get ("wrapper-null-handler")) - { - os << "if (composite_value_traits< " << mi.fq_type () << - ", id_" << db << " >::get_null (" << endl - << "i." << mi.var << "value" << - (versioned (*comp) ? ", svm" : "") << "))" << endl - << "wrapper_traits< " << wt << " >::set_null (" << member + ");" - << "else" - << "{"; - } - - os << mi.fq_type () << "& vw =" << endl - << " wrapper_traits< " + wt + " >::set_ref (" + member + ");" - << endl; - - wrap_member = member; - member = "vw"; - } - - if (mi.ptr != 0) - { - type = "obj_traits::id_type"; - - // Handle NULL pointers and extract the id. - // - os << "typedef object_traits< " << class_fq_name (*mi.ptr) << - " > obj_traits;" - << "typedef odb::pointer_traits< " << mi.ptr_fq_type () << - " > ptr_traits;" - << endl; - - os << "if ("; - - if (comp != 0) - os << "composite_value_traits< " << type << ", id_" << db << - " >::get_null (" << endl - << "i." << mi.var << "value" << - (versioned (*comp) ? ", svm" : "") << ")"; - else - get_null (mi.var); - - os << ")" << endl; - - // Don't throw null_pointer if we can't have NULLs and the pointer - // is NULL since this can be useful during migration. Instead, we - // rely on the database enforcing this. - // - os << member << " = ptr_traits::pointer_type ();"; - - os << "else" - << "{"; - - os << type << " ptr_id;"; - - member = "ptr_id"; - } - else - type = mi.fq_type (); - - if (comp != 0) - traits = "composite_value_traits< " + type + ", id_" + - db.string () + " >"; - else - { - db_type_id = member_database_type_id_->database_type_id (mi.m); - traits = db.string () + "::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - - virtual void - post (member_info& mi) - { - if (mi.ptr != 0) - { - if (view_member (mi.m)) - { - // The object pointer in view doesn't need any of this. - os << "}"; - return; - } - - // Restore the member variable name. - // - member = member_override_.empty () ? "v" : member_override_; - - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& pt (utype (mi.m, key_prefix_)); - - if (lazy_pointer (pt)) - os << member << " = ptr_traits::pointer_type (" << endl - << "*static_cast<" << db << "::database*> (db), ptr_id);"; - else - { - os << "// If a compiler error points to the line below, then" << endl - << "// it most likely means that a pointer used in a member" << endl - << "// cannot be initialized from an object pointer." << endl - << "//" << endl - << member << " = ptr_traits::pointer_type (" << endl - << "static_cast<" << db << "::database*> (db)->load<" << endl - << " obj_traits::object_type > (ptr_id));"; - - // If we are loading into an eager weak pointer, make sure there - // is someone else holding a strong pointer to it (normally a - // session). Otherwise, the object will be loaded and immediately - // deleted. Besides not making much sense, this also breaks the - // delayed loading machinery which expects the object to be around - // at least until the top-level load() returns. - // - if (weak_pointer (pt)) - { - os << endl - << "if (odb::pointer_traits<" << - "ptr_traits::strong_pointer_type>::null_ptr (" << endl - << "ptr_traits::lock (" << member << ")))" << endl - << "throw session_required ();"; - } - } - - os << "}"; - } - - // Wrap back (so to speak). - // - if (mi.wrapper != 0 && composite (mi.t) != 0) - { - if (null (mi.m, key_prefix_) && - mi.wrapper->template get ("wrapper-null-handler")) - os << "}"; - - member = wrap_member; - } - - // Untranslate. - // - if (mi.ct != 0) - { - //@@ Use move() in C++11? Or not. - // - os << "// From " << location_string (mi.ct->loc, true) << endl - << translate_member << " = " << - mi.ct->translate_from (member) << ";"; - - member = translate_member; - } - - // Call the modifier if we are using a proper one. - // - if (member_override_.empty ()) - { - member_access& ma (mi.m.template get ("set")); - - if (ma.placeholder ()) - { - // If this is not a synthesized expression, then output its - // location for easier error tracking. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - os << ma.translate ( - "o", "v", "*static_cast<" + db.string () + "::database*> (db)") - << ";"; - } - } - - os << "}"; - } - - virtual void - traverse_pointer (member_info& mi) - { - // Object pointers in views require special treatment. - // - if (view_member (mi.m)) - { - // This is the middle part. The pre and post parts are generated - // by init_view_pointer_member below. - // - using semantics::class_; - - class_& c (*mi.ptr); - class_* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - - string o_tp (mi.var + "object_type"); - string o_tr (mi.var + "object_traits"); - string r_tr (poly_derived ? mi.var + "root_traits" : o_tr); - string i_tp (mi.var + "info_type"); - - string id (mi.var + "id"); - string o (mi.var + "o"); - string pi (mi.var + "pi"); // Polymorphic type info. - - // If load_() will be loading containers or the rest of the - // polymorphic object, then we need to perform several extra - // things. We need to initialize the id image in the object - // statements. We also have to lock the statements so that - // nobody messes up this id image. - // - bool init_id ( - poly || - has_a (c, test_container | include_eager_load, &main_section)); - - bool versioned (context::versioned (c)); - - os << "if (" << o << " != 0)" - << "{"; - - if (poly) - os << "callback_event ce (callback_event::pre_load);" - << pi << "->dispatch (" << i_tp << "::call_callback, " << - "*db, " << o << ", &ce);"; - else - os << o_tr << "::callback (*db, *" << o << - ", callback_event::pre_load);"; - - os << o_tr << "::init (*" << o << ", i." << mi.var << "value, db" << - (versioned ? ", svm" : "") << ");"; - - // Call load_() to load the rest of the object (containers, etc). - // - if (id_member (poly ? *poly_root : c) != 0) - { - const char* s (poly_derived ? "osts" : "sts"); - - os << o_tr << "::statements_type& " << s << " (" << endl - << "conn.statement_cache ().find_object<" << o_tp << "> ());"; - - if (poly_derived) - os << r_tr << "::statements_type& sts (osts.root_statements ());"; - - if (init_id) - { - // This can only be top-level call so lock must succeed. - // - os << r_tr << "::statements_type::auto_lock l (sts);" - << "assert (l.locked ()) /* Must be a top-level call. */;" - << endl - << r_tr << "::id_image_type& i (sts.id_image ());" - << r_tr << "::init (i, " << id << ");" - << db << "::binding& idb (sts.id_image_binding ());" - << "if (i.version != sts.id_image_version () || " << - "idb.version == 0)" - << "{" - << r_tr << "::bind (idb.bind, i);" - << "sts.id_image_version (i.version);" - << "idb.version++;"; - if (optimistic (poly ? *poly_root : c) != 0) - os << "sts.optimistic_id_image_binding ().version++;"; - os << "}"; - } - - os << o_tr << "::load_ (" << s << ", *" << o << ", false" << - (versioned ? ", svm" : "") << ");"; - - // Load the dynamic part of the object unless static and dynamic - // types are the same. - // - if (poly) - os << endl - << "if (" << pi << " != &" << o_tr << "::info)" - << "{" - << "std::size_t d (" << o_tr << "::depth);" - << pi << "->dispatch (" << i_tp << "::call_load, *db, " << - o << ", &d);" - << "}"; - - if (init_id) - os << "sts.load_delayed (" << (versioned ? "&svm" : "0") << ");" - << "l.unlock ();"; - } - - os << "}"; - } - else - member_base_impl::traverse_pointer (mi); - } - - virtual void - traverse_composite (member_info& mi) - { - os << traits << "::init (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "db"; - - if (versioned (*composite (mi.t))) - os << "," << endl - << "svm"; - - os << ");" - << endl; - } - - protected: - string type; - string db_type_id; - string traits; - string member; - string translate_member; // Untranslated member. - string wrap_member; // Wrapped member. - - instance member_database_type_id_; - }; - - // This class generates the pre and post parts. The middle part is - // generated by init_value_member above. - // - struct init_view_pointer_member: virtual member_base, - member_base_impl // Dummy SQL type. - { - typedef init_view_pointer_member base; - - init_view_pointer_member (bool pre, init_value_member const& ivm) - : member_base (0, 0, string (), string (), 0), - pre_ (pre), init_value_member_ (ivm) {} - - virtual bool - pre (member_info& mi) - { - // Only interested in object pointers inside views. - // - return mi.ptr != 0 && view_member (mi.m); - } - - virtual void - traverse_pointer (member_info& mi) - { - using semantics::class_; - - class_& c (*mi.ptr); - bool abst (abstract (c)); - class_* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - size_t poly_depth (poly_derived ? polymorphic_depth (c) : 1); - - data_member_path* idm (id_member (poly ? *poly_root : c)); - - os << "// " << mi.m.name () << (pre_ ? " pre" : " post") << endl - << "//" << endl; - - string o_tp (mi.var + "object_type"); - string o_tr (mi.var + "object_traits"); - string r_tr (poly_derived ? mi.var + "root_traits" : o_tr); - string i_tp (mi.var + "info_type"); - string p_tp (mi.var + "pointer_type"); - string p_tr (mi.var + "pointer_traits"); - string c_tr (mi.var + "cache_traits"); - - string id (mi.var + "id"); // Object id. - string p (mi.var + "p"); // Object pointer. - string pg (mi.var + "pg"); // Pointer guard. - string ig (mi.var + "ig"); // Cache insert guard. - string o (mi.var + "o"); // Object. - string pi (mi.var + "pi"); // Polymorphic type info. - - bool op_raw (c.get ("object-pointer-raw")); - bool mp_raw (utype (mi.m).is_a ()); - - // Output aliases and variables before any schema version if- - // blocks since we need to be able to access them across all - // three parts. - // - if (pre_) - { - os << "typedef " << class_fq_name (c) << " " << o_tp << ";" - << "typedef object_traits_impl<" << o_tp << ", id_" << db << - "> " << o_tr << ";"; - - if (poly_derived) - os << "typedef " << o_tr << "::root_traits " << r_tr << ";"; - - if (poly) - os << "typedef " << r_tr << "::info_type " << i_tp << ";"; - - os << "typedef " << r_tr << "::pointer_type " << p_tp << ";" - << "typedef " << r_tr << "::pointer_traits " << p_tr << ";"; - if (idm != 0) - os << "typedef " << r_tr << "::pointer_cache_traits " << - c_tr << ";"; - os << endl; - - if (idm != 0) - os << r_tr << "::id_type " << id << ";"; - os << p_tp << " " << p << (op_raw ? " = 0" : "") << ";" // VC++ - << p_tr << "::guard " << pg << ";"; - if (idm != 0) - os << c_tr << "::insert_guard " << ig << ";"; - os << o_tp << "* " << o << " (0);"; - - if (poly) - os << "const " << i_tp << "* " << pi << " = 0;"; // VC++ - - os << endl; - } - - // 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 << ")"; - } - - os << "{"; - - if (pre_) - { - string id_im; - if (idm != 0) - { - // Check for NULL. - // - string id_var; - { - id_im = mi.var + "value"; - - // In a polymorphic class, the id is in the root image. - // - for (size_t i (0); i < poly_depth - 1; ++i) - id_im += (i == 0 ? ".base" : "->base"); - - string n; - for (data_member_path::const_iterator i (idm->begin ()); - i != idm->end (); - ++i) - { - // The same logic as in member_base. - // - if (!n.empty ()) - n += "value."; // Composite. - - string const& name ((*i)->name ()); - n += name; - - if (n[n.size () - 1] != '_') - n += '_'; - } - - id_var = id_im + (poly_derived ? "->" : ".") + n; - id_im = (poly_derived ? "*i." : "i.") + id_im; - } - - os << "if ("; - - if (semantics::class_* comp = composite (mi.t)) - os << "!composite_value_traits< " << o_tr << "::id_type, id_" << - db << " >::get_null (" << endl - << "i." << id_var << "value" << - (versioned (*comp) ? ", svm" : "") << ")"; - else - { - os << "!("; - init_value_member_.get_null (id_var); - os << ")"; - } - - os << ")" - << "{"; - - // Check cache. - // - os << id << " = " << r_tr << "::id (" << id_im << ");" - << p << " = " << c_tr << "::find (*db, " << id << ");" - << endl; - - os << "if (" << p_tr << "::null_ptr (" << p << "))" - << "{"; - } - - // To support by-value object loading, we are going to load - // into an existing instance if the pointer is already not - // NULL. To limit the potential misuse (especially when it - // comes to sessions), we are going to limit this support - // only to raw pointers. Furthermore, we will only insert - // such an object into the cache if its object pointer is - // also raw. - // - if (mp_raw && !poly) - { - // Get the member using the accessor expression. - // - member_access& ma (mi.m.get ("get")); - - // If this is not a synthesized expression, then output - // its location for easier error tracking. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - // Use the original type to form the const reference. VC++ - // cannot grok the constructor syntax. - // - os << member_ref_type (mi.m, true, "m") << " =" << endl - << " " << ma.translate ("o") << ";" - << endl; - - os << "if (m != 0)" - << "{"; - - if (op_raw) - os << ig << ".reset (" << c_tr << "::insert (*db, " << id << - ", m));"; - - os << o << " = m;" - << "}" - << "else" - << "{"; - } - - if (poly) - { - os << r_tr << "::discriminator_type d (" << endl - << r_tr << "::discriminator (" << id_im << "));"; - - if (abst) - os << pi << " = &" << r_tr << "::map->find (d);"; - else - os << pi << " = (d == " << o_tr << "::info.discriminator" << endl - << "? &" << o_tr << "::info" << endl - << ": &" << r_tr << "::map->find (d));"; - - os << p << " = " << pi << "->create ();"; - } - else - os << p << " = object_factory<" << o_tp << ", " << p_tp << - ">::create ();"; - - os << pg << ".reset (" << p << ");"; - if (idm != 0) - os << ig << ".reset (" << c_tr << "::insert (*db, " << id << - ", " << p << "));"; - - if (poly_derived) - os << o << " = static_cast<" << o_tp << "*> (" << p_tr << - "::get_ptr (" << p << "));"; - else - os << o << " = " << p_tr << "::get_ptr (" << p << ");"; - - if (mp_raw && !poly) - os << "}"; - - if (idm != 0) - os << "}" // Cache. - << "}"; // NULL. - } - else - { - os << "if (" << o << " != 0)" - << "{"; - - if (poly) - os << "callback_event ce (callback_event::post_load);" - << pi << "->dispatch (" << i_tp << "::call_callback, " << - "*db, " << o << ", &ce);"; - else - os << o_tr << "::callback (*db, *" << o << - ", callback_event::post_load);"; - - if (idm != 0) - { - if (mp_raw && !op_raw && !poly) - os << "if (!" << p_tr << "::null_ptr (" << p << "))" - << "{"; - - os << c_tr << "::load (" << ig << ".position ());" - << ig << ".release ();"; - - if (mp_raw && !op_raw && !poly) - os << "}"; - } - - os << pg << ".release ();"; - - os << "}"; - - // If member pointer is not raw, then result is in p. - // If both member and object are raw, then result is in o. - // If member is raw but object is not, then result is in - // p if it is not NULL, and in o (either NULL or the same - // as the member value) otherwise. - // - member_access& ma (mi.m.get ("set")); - - if (ma.empty () && !poly) - { - // It is ok to have empty modifier expression as long as - // the member pointer is raw. This is the by-value load - // and the user is not interested in learning whether the - // object is NULL. - // - if (!mp_raw) - { - error (ma.loc) << "non-empty modifier expression required " << - "for loading an object via a smart pointer" << endl; - throw operation_failed (); - } - - os << "// Empty modifier expression was specified for this\n" - << "// object so make sure we have actually loaded the\n" - << "// data into the existing instance rather than, say,\n" - << "// finding the object in the cache or creating a new one.\n" - << "//\n" - << "assert (" << p_tr << "::null_ptr (" << p << "));"; - } - else - { - if (!(mp_raw && op_raw) || poly) - { - string r (options.std () >= cxx_version::cxx11 - ? "std::move (" + p + ")" - : p); - - if (poly_derived) - // This pointer could have come from cache, so use dynamic - // cast. - // - r = p_tr + "::dynamic_pointer_cast<" + o_tp + "> (\n" + - r + ")"; - - // Unless the pointer is raw, explicitly construct the - // smart pointer from the object pointer so that we get - // the behavior similar to calling database::load() (in - // both cases we are the "ownership end-points"; unless - // the object was already in the session before loading - // this view (in which case using raw pointers as object - // pointers is a really stupid idea), this logic will do - // the right thing and what the user most likely expects. - // - if (!mp_raw) - r = member_val_type (mi.m, false) + " (\n" + r + ")"; - - if (mp_raw && !op_raw) - os << "if (!" << p_tr << "::null_ptr (" << p << "))" << endl; - - os << "// If a compiler error points to the line below, then\n" - << "// it most likely means that a pointer used in view\n" - << "// member cannot be initialized from an object pointer.\n" - << "//" << endl; - - set_member (mi.m, "o", r, "db"); - } - - if (mp_raw && !poly) - { - if (!op_raw) - os << "else" << endl; // NULL p - - set_member (mi.m, "o", o, "db"); - } - } - } - - os << "}"; - } - - virtual bool const& - member_sql_type (semantics::data_member&) {return pre_;}; - - protected: - bool pre_; - init_value_member const& init_value_member_; - }; - - struct init_value_base: traversal::class_, virtual context - { - typedef init_value_base base; - - virtual void - traverse (type& c) - { - bool obj (object (c)); - - // Ignore transient bases. Not used for views. - // - if (!(obj || composite (c))) - return; - - os << "// " << class_name (c) << " base" << endl - << "//" << endl; - - if (obj) - os << "object_traits_impl< "; - else - os << "composite_value_traits< "; - - os << class_fq_name (c) << ", id_" << db << " >::init (o, i, db" << - (versioned (c) ? ", svm" : "") << ");" - << endl; - } - }; - - // Member-specific traits types for container members. - // - struct container_traits: object_members_base, virtual context - { - typedef container_traits base; - - container_traits (semantics::class_& c) - : object_members_base ( - true, - object (c), // Only build table prefix for objects. - false), - c_ (c) - { - scope_ = object (c) - ? "access::object_traits_impl< " - : "access::composite_value_traits< "; - - scope_ += class_fq_name (c) + ", id_" + db.string () + " >"; - } - - // Unless the database system can execute several interleaving - // statements, cache the result set. - // - virtual void - cache_result (string const& statement) - { - os << statement << ".cache ();"; - } - - // Additional code that need to be executed following the call to - // init_value. - // - virtual void - init_value_extra () - { - } - - virtual void - process_statement_columns (statement_columns&, - statement_kind, - bool /*dynamic*/) - { - } - - virtual void - traverse_pointer (semantics::data_member&, semantics::class_&) - { - // We don't want to traverse composite id. - } - - virtual void - traverse_composite (semantics::data_member* m, semantics::class_& c) - { - if (object (c_)) - object_members_base::traverse_composite (m, c); - else - { - // If we are generating traits for a composite value type, then - // we don't want to go into its bases or it composite members. - // - if (m == 0 && &c == &c_) - names (c); - } - } - - virtual void - container_extra (semantics::data_member&, semantics::type&) - { - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type& t) - { - using semantics::type; - - // Figure out if this member is from a base object or composite - // value and if it's from an object, whether it is reuse-abstract. - // - bool base, reuse_abst; - - if (object (c_)) - { - base = cur_object != &c_ || - !object (dynamic_cast (m.scope ())); - reuse_abst = abstract (c_) && !polymorphic (c_); - } - else - { - base = false; // We don't go into bases. - reuse_abst = true; // Always abstract. - } - - container_kind_type ck (container_kind (t)); - - const custom_cxx_type* vct (0); - const custom_cxx_type* ict (0); - const custom_cxx_type* kct (0); - - type& vt (container_vt (m, &vct)); - type* it (0); - type* kt (0); - - data_member_path* imp (context::inverse (m, "value")); - - bool ordered (false); - bool inverse (imp != 0); - bool grow (false); - - switch (ck) - { - case ck_ordered: - { - if (!unordered (m)) - { - it = &container_it (m, &ict); - ordered = true; - - if (generate_grow) - grow = grow || context::grow (m, *it, ict, "index"); - } - - break; - } - case ck_map: - case ck_multimap: - { - kt = &container_kt (m, &kct); - - if (generate_grow) - grow = grow || context::grow (m, *kt, kct, "key"); - - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - bool smart (!inverse && - (ck != ck_ordered || ordered) && - container_smart (t)); - - if (generate_grow) - grow = grow || context::grow (m, vt, vct, "value"); - - bool eager_ptr (is_a (member_path_, - member_scope_, - test_eager_pointer, - vt, - "value")); - if (!eager_ptr) - { - if (semantics::class_* cvt = composite_wrapper (vt)) - eager_ptr = has_a (*cvt, test_eager_pointer); - } - - bool versioned (context::versioned (m)); - - string name (flat_prefix_ + public_name (m) + "_traits"); - string scope (scope_ + "::" + name); - - os << "// " << m.name () << endl - << "//" << endl - << endl; - - container_extra (m, t); - - // - // Statements. - // - if (!reuse_abst) - { - string sep (versioned ? "\n" : " "); - - semantics::type& idt (container_idt (m)); - - qname table (table_name (m, table_prefix_)); - string qtable (quote_id (table)); - instance id_cols; - instance ik_cols; // index/key columns - - if (smart) - { - switch (ck) - { - case ck_ordered: - { - ik_cols->traverse (m, *it, "index", "index"); - break; - } - case ck_map: - case ck_multimap: - { - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - } - - // select_statement - // - os << "const char " << scope << "::" << endl - << "select_statement[] =" << endl; - - if (inverse) - { - semantics::class_* c (object_pointer (vt)); - semantics::data_member& imf (*imp->front ()); - semantics::data_member& imb (*imp->back ()); - - // In a polymorphic hierarchy the inverse member can be in - // the base class, in which case we should use that class - // for the table name, etc. - // - if (polymorphic (*c)) - c = &dynamic_cast (imf.scope ()); - - data_member_path& inv_id (*id_member (*c)); - - qname inv_table; // Other table name. - string inv_qtable; - instance inv_id_cols; // Other id column. - instance inv_fid_cols; // Other foreign id - // column (ref to us). - statement_columns sc; - - if (container (imb)) - { - // many(i)-to-many - // - - // This other container is a direct member of the class so the - // table prefix is just the class table name. - // - inv_table = table_name (*c, *imp); - inv_qtable = quote_id (inv_table); - - inv_id_cols->traverse (imb, utype (inv_id), "id", "object_id", c); - inv_fid_cols->traverse (imb, idt, "value", "value"); - - for (object_columns_list::iterator i (inv_id_cols->begin ()); - i != inv_id_cols->end (); ++i) - { - // If this is a simple id, then pass the "id" key prefix. If - // it is a composite id, then the members have no prefix. - // - sc.push_back ( - statement_column ( - inv_qtable, - inv_qtable + "." + quote_id (i->name), - i->type, - *i->member, - inv_id_cols->size () == 1 ? "id" : "")); - } - } - else - { - // many(i)-to-one - // - inv_table = table_name (*c); - inv_qtable = quote_id (inv_table); - - inv_id_cols->traverse (inv_id); - inv_fid_cols->traverse (imb, column_prefix (*imp)); - - for (object_columns_list::iterator i (inv_id_cols->begin ()); - i != inv_id_cols->end (); ++i) - { - sc.push_back ( - statement_column ( - inv_qtable, - inv_qtable + "." + quote_id (i->name), - i->type, - *i->member)); - } - } - - process_statement_columns (sc, statement_select, versioned); - - os << strlit ("SELECT" + sep) << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - instance qp (statement_select, inv_table); - os << strlit ("FROM " + inv_qtable + sep) << endl; - - string where ("WHERE "); - for (object_columns_list::iterator b (inv_fid_cols->begin ()), - i (b); i != inv_fid_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += inv_qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - os << strlit (where); - } - else - { - id_cols->traverse (m, idt, "id", "object_id"); - - statement_columns sc; - statement_kind sk (statement_select); // Imperfect forwarding. - instance t (qtable, sk, sc); - - switch (ck) - { - case ck_ordered: - { - if (ordered) - t->traverse (m, *it, "index", "index"); - break; - } - case ck_map: - case ck_multimap: - { - t->traverse (m, *kt, "key", "key"); - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - t->traverse (m, vt, "value", "value"); - - process_statement_columns (sc, statement_select, versioned); - - os << strlit ("SELECT" + sep) << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - instance qp (statement_select, table); - os << strlit ("FROM " + qtable + sep) << endl; - - string where ("WHERE "); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - if (ordered) - { - // Top-level column. - // - string const& col ( - column_qname (m, "index", "index", column_prefix ())); - - where += " ORDER BY " + qtable + "." + col; - } - - os << strlit (where); - } - - os << ";" - << endl; - - // insert_statement - // - os << "const char " << scope << "::" << endl - << "insert_statement[] =" << endl; - - if (inverse) - os << strlit ("") << ";" - << endl; - else - { - statement_columns sc; - statement_kind sk (statement_insert); // Imperfect forwarding. - instance t (sk, sc); - - t->traverse (m, idt, "id", "object_id"); - - switch (ck) - { - case ck_ordered: - { - if (ordered) - t->traverse (m, *it, "index", "index"); - break; - } - case ck_map: - case ck_multimap: - { - t->traverse (m, *kt, "key", "key"); - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - t->traverse (m, vt, "value", "value"); - - process_statement_columns (sc, statement_insert, versioned); - - os << strlit ("INSERT INTO " + qtable + sep) << endl; - - for (statement_columns::const_iterator b (sc.begin ()), i (b), - e (sc.end ()); i != e;) - { - string s; - - if (i == b) - s += '('; - s += i->column; - s += (++i != e ? ',' : ')'); - s += sep; - - os << strlit (s) << endl; - } - - os << strlit ("VALUES" + sep) << endl; - - string values ("("); - instance qp (statement_insert, table); - for (statement_columns::const_iterator b (sc.begin ()), i (b), - e (sc.end ()); i != e; ++i) - { - if (i != b) - { - values += ','; - values += sep; - } - - values += convert_to (qp->next (*i), i->type, *i->member); - } - values += ')'; - - os << strlit (values) << ";" - << endl; - } - - // update_statement - // - if (smart) - { - os << "const char " << scope << "::" << endl - << "update_statement[] =" << endl - << strlit ("UPDATE " + qtable + sep) << endl - << strlit ("SET" + sep) << endl; - - instance qp (statement_update, table); - statement_columns sc; - { - bool f (false); // Imperfect forwarding. - query_parameters* p (qp.get ()); // Imperfect forwarding. - statement_kind sk (statement_update); // Imperfect forwarding. - instance t (sk, f, sc, p); - t->traverse (m, vt, "value", "value"); - process_statement_columns (sc, statement_update, versioned); - } - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - string where ("WHERE "); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - for (object_columns_list::iterator b (ik_cols->begin ()), i (b); - i != ik_cols->end (); ++i) - { - where += " AND " + quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - os << strlit (where) << ";" - << endl; - } - - // delete_statement - // - os << "const char " << scope << "::" << endl - << "delete_statement[] =" << endl; - - if (inverse) - os << strlit ("") << ";" - << endl; - else - { - instance qp (statement_delete, table); - - os << strlit ("DELETE FROM " + qtable + " ") << endl; - - string where ("WHERE "); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - if (smart) - { - for (object_columns_list::iterator b (ik_cols->begin ()), i (b); - i != ik_cols->end (); ++i) - { - where += " AND " + quote_id (i->name) + - (ck == ck_ordered ? ">=" : "=") + - convert_to (qp->next (*i), i->type, *i->member); - } - } - - os << strlit (where) << ";" - << endl; - } - } - - if (base) - return; - - // - // Functions. - // - - // bind (cond_image_type) - // - if (smart) - { - os << "void " << scope << "::" << endl - << "bind (" << bind_vector << " b," << endl - << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl - << "cond_image_type& c)" - << "{" - << "using namespace " << db << ";" - << endl - << "statement_kind sk (statement_select);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl - << "std::size_t n (0);" - << endl; - - os << "// object_id" << endl - << "//" << endl - << "if (id != 0)" << endl - << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));" - << "n += id_size;" // Not in if for "id unchanged" optimization. - << endl; - - // We don't need to update the bind index since this is the - // last element. - // - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl; - instance bm ( - "index_", "c", *it, ict, "index_type", "index"); - bm->traverse (m); - } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - instance bm ( - "key_", "c", *kt, kct, "key_type", "key"); - bm->traverse (m); - break; - } - case ck_set: - case ck_multiset: - { - os << "// value" << endl - << "//" << endl; - instance bm ( - "value_", "c", vt, vct, "value_type", "value"); - bm->traverse (m); - break; - } - } - os << "}"; - } - - // bind (data_image_type) - // - { - os << "void " << scope << "::" << endl - << "bind (" << bind_vector << " b," << endl - << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl - << "data_image_type& d"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << endl - // In the case of containers, insert and select column sets are - // the same since we can't have inverse members as container - // elements. - // - << "statement_kind sk (statement_select);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl - << "size_t n (0);" - << endl; - - os << "// object_id" << endl - << "//" << endl - << "if (id != 0)" << endl - << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));" - << "n += id_size;" // Not in if for "id unchanged" optimization. - << endl; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl; - instance bm ( - "index_", "d", *it, ict, "index_type", "index"); - bm->traverse (m); - os << "n++;" // Simple value. - << endl; - } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - instance bm ( - "key_", "d", *kt, kct, "key_type", "key"); - bm->traverse (m); - - if (semantics::class_* c = composite_wrapper (*kt)) - os << "n += " << column_count (*c).total << "UL;" - << endl; - else - os << "n++;" - << endl; - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - // We don't need to update the bind index since this is the - // last element. - // - os << "// value" << endl - << "//" << endl; - instance bm ( - "value_", "d", vt, vct, "value_type", "value"); - bm->traverse (m); - - os << "}"; - } - - // bind (cond_image, data_image) (update) - // - if (smart) - { - os << "void " << scope << "::" << endl - << "bind (" << bind_vector << " b," << endl - << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl - << "cond_image_type& c," << endl - << "data_image_type& d"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << endl - // Use insert instead of update to include read-only members. - // - << "statement_kind sk (statement_insert);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl - << "std::size_t n (0);" - << endl; - - os << "// value" << endl - << "//" << endl; - instance bm ( - "value_", "d", vt, vct, "value_type", "value"); - bm->traverse (m); - - if (semantics::class_* c = composite_wrapper (vt)) - os << "n += " << column_count (*c).total << "UL;" - << endl; - else - os << "n++;" - << endl; - - os << "// object_id" << endl - << "//" << endl - << "if (id != 0)" << endl - << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));" - << "n += id_size;" // Not in if for "id unchanged" optimization. - << endl; - - // We don't need to update the bind index since this is the - // last element. - // - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl; - instance bm ( - "index_", "c", *it, ict, "index_type", "index"); - bm->traverse (m); - } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - instance bm ( - "key_", "c", *kt, kct, "key_type", "key"); - bm->traverse (m); - break; - } - case ck_set: - case ck_multiset: - { - os << "// value" << endl - << "//" << endl; - instance bm ( - "value_", "c", vt, vct, "value_type", "value"); - bm->traverse (m); - break; - } - } - os << "}"; - } - - // grow () - // - if (generate_grow) - { - size_t index (0); - - os << "void " << scope << "::" << endl - << "grow (data_image_type& i," << endl - << truncated_vector << " t"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "bool grew (false);" - << endl; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl; - instance gm ( - index, "index_", *it, ict, "index_type", "index"); - gm->traverse (m); - } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - instance gm ( - index, "key_", *kt, kct, "key_type", "key"); - gm->traverse (m); - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - os << "// value" << endl - << "//" << endl; - instance gm ( - index, "value_", vt, vct, "value_type", "value"); - gm->traverse (m); - - os << "if (grew)" << endl - << "i.version++;" - << "}"; - } - - // init (data_image) - // - if (!inverse) - { - os << "void " << scope << "::" << endl - << "init (data_image_type& i," << endl; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - os << "index_type* j," << endl; - break; - } - case ck_map: - case ck_multimap: - { - os << "const key_type* k," << endl; - break; - } - case ck_set: - case ck_multiset: - break; - } - - os << "const value_type& v"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << endl - << "statement_kind sk (statement_insert);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl; - - if (generate_grow) - os << "bool grew (false);" - << endl; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl - << "if (j != 0)"; - - instance im ( - "index_", "*j", *it, ict, "index_type", "index"); - im->traverse (m); - } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl - << "if (k != 0)"; - - instance im ( - "key_", "*k", *kt, kct, "key_type", "key"); - im->traverse (m); - - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - os << "// value" << endl - << "//" << endl; - { - instance im ( - "value_", "v", vt, vct, "value_type", "value"); - im->traverse (m); - } - - if (generate_grow) - os << "if (grew)" << endl - << "i.version++;"; - - os << "}"; - } - - // init (cond_image) - // - if (smart) - { - os << "void " << scope << "::" << endl; - - switch (ck) - { - case ck_ordered: - { - os << "init (cond_image_type& i, index_type j)" - << "{" - << "using namespace " << db << ";" - << endl - << "statement_kind sk (statement_select);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl; - - instance im ( - "index_", "j", *it, ict, "index_type", "index"); - im->traverse (m); - - os << "}"; - break; - } - case ck_map: - case ck_multimap: - { - // Need to handle growth. - // - // os << "init (data_image_type&, const key_type&);"; - break; - } - case ck_set: - case ck_multiset: - { - // Need to handle growth. - // - // os << "init (data_image_type&, const value_type&);"; - break; - } - } - - os << endl; - } - - // init (data) - // - os << "void " << scope << "::" << endl - << "init ("; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - os << "index_type& j," << endl; - break; - } - case ck_map: - case ck_multimap: - { - os << "key_type& k," << endl; - break; - } - case ck_set: - case ck_multiset: - break; - } - - os << "value_type& v," << endl; - os << "const data_image_type& i," << endl - << "database* db"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (db);" - << endl; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl; - - instance im ( - "index_", "j", *it, ict, "index_type", "index"); - im->traverse (m); - } - - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - - instance im ( - "key_", "k", *kt, kct, "key_type", "key"); - im->traverse (m); - - break; - } - case ck_set: - case ck_multiset: - break; - } - - os << "// value" << endl - << "//" << endl; - { - // If the value is an object pointer, pass the id type as a - // type override. - // - instance im ( - "value_", "v", vt, vct, "value_type", "value"); - im->traverse (m); - } - os << "}"; - - // insert - // - { - string ia, ka, va, da; - - if (!inverse) - { - ia = ordered ? " i" : ""; - ka = " k"; - va = " v"; - da = " d"; - } - - os << "void " << scope << "::" << endl; - - switch (ck) - { - case ck_ordered: - { - os << "insert (index_type" << ia << ", " << - "const value_type&" << va << ", " << - "void*" << da << ")"; - break; - } - case ck_map: - case ck_multimap: - { - os << "insert (const key_type&" << ka << ", " << - "const value_type&" << va << ", " << - "void*" << da << ")"; - break; - } - case ck_set: - case ck_multiset: - { - os << "insert (const value_type&" << va << ", " << - "void*" << da << ")"; - break; - } - } - - os << "{"; - - if (!inverse) - { - os << "using namespace " << db << ";" - << endl - << "statements_type& sts (*static_cast< statements_type* > (d));" - << "data_image_type& di (sts.data_image ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration ());"; - - os << endl - << "init (di, "; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - os << "&i, "; - break; - } - case ck_map: - case ck_multimap: - { - os << "&k, "; - break; - } - case ck_set: - case ck_multiset: - break; - } - - os << "v" << (versioned ? ", svm" : "") << ");"; - - os << endl - << "if (sts.data_binding_test_version ())" - << "{" - << "const binding& id (sts.id_binding ());" - << "bind (sts.data_bind (), id.bind, id.count, di" << - (versioned ? ", svm" : "") << ");" - << "sts.data_binding_update_version ();" - << "}" - << "if (!sts.insert_statement ().execute ())" << endl - << "throw object_already_persistent ();"; - } - - os << "}"; - } - - // update - // - if (smart) - { - os << "void " << scope << "::" << endl; - - switch (ck) - { - case ck_ordered: - { - os << "update (index_type i, const value_type& v, void* d)"; - break; - } - case ck_map: - case ck_multimap: - { - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - os << "{"; - - os << "using namespace " << db << ";" - << endl - << "statements_type& sts (*static_cast< statements_type* > (d));" - << "cond_image_type& ci (sts.cond_image ());" - << "data_image_type& di (sts.data_image ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration ());"; - - os << endl; - - switch (ck) - { - case ck_ordered: - { - os << "init (ci, i);"; - os << "init (di, 0, v" << (versioned ? ", svm" : "") << ");"; - break; - } - case ck_map: - case ck_multimap: - { - //os << "init (di, 0, v);"; - break; - } - case ck_set: - case ck_multiset: - { - //os << "init (di, v);"; - break; - } - } - - os << endl - << "if (sts.update_binding_test_version ())" - << "{" - << "const binding& id (sts.id_binding ());" - << "bind (sts.update_bind (), id.bind, id.count, ci, di" << - (versioned ? ", svm" : "") << ");" - << "sts.update_binding_update_version ();" - << "}"; - - os << "if (sts.update_statement ().execute () == 0)" << endl - << "throw object_not_persistent ();" - << "}"; - } - - // select - // - os << "bool " << scope << "::" << endl; - - switch (ck) - { - case ck_ordered: - { - os << "select (index_type&" << (ordered ? " i" : "") << - ", value_type& v, void* d)"; - break; - } - case ck_map: - case ck_multimap: - { - os << "select (key_type& k, value_type& v, void* d)"; - break; - } - case ck_set: - case ck_multiset: - { - os << "select (value_type& v, void* d)"; - break; - } - } - - os << "{" - << "using namespace " << db << ";" - << "using " << db << "::select_statement;" // Conflicts. - << endl - << "statements_type& sts (*static_cast< statements_type* > (d));" - << "data_image_type& di (sts.data_image ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration ());"; - - os << endl - << "init ("; - - // Extract current element. - // - switch (ck) - { - case ck_ordered: - { - if (ordered) - os << "i, "; - break; - } - case ck_map: - case ck_multimap: - { - os << "k, "; - break; - } - case ck_set: - case ck_multiset: - break; - } - - os << "v, di, &sts.connection ().database ()" << - (versioned ? ", svm" : "") << ");" - << endl; - - init_value_extra (); - - // If we are loading an eager pointer, then the call to init - // above executes other statements which potentially could - // change the image, including the id. - // - if (eager_ptr) - { - os << "if (sts.data_binding_test_version ())" - << "{" - << "const binding& id (sts.id_binding ());" - << "bind (sts.data_bind (), id.bind, id.count, di" << - (versioned ? ", svm" : "") << ");" - << "sts.data_binding_update_version ();" - << "}"; - } - - // Fetch next. - // - os << "select_statement& st (sts.select_statement ());" - << "select_statement::result r (st.fetch ());"; - - if (grow) - os << endl - << "if (r == select_statement::truncated)" - << "{" - << "grow (di, sts.select_image_truncated ()" << - (versioned ? ", svm" : "") << ");" - << endl - << "if (sts.data_binding_test_version ())" - << "{" - // Id cannot change. - // - << "bind (sts.data_bind (), 0, sts.id_binding ().count, di" << - (versioned ? ", svm" : "") << ");" - << "sts.data_binding_update_version ();" - << "st.refetch ();" - << "}" - << "}"; - - os << "return r != select_statement::no_data;" - << "}"; - - // delete_ - // - os << "void " << scope << "::" << endl - << "delete_ ("; - - if (smart) - { - switch (ck) - { - case ck_ordered: - { - os << "index_type i, "; - break; - } - case ck_map: - case ck_multimap: - { - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - } - - os << "void*" << (inverse ? "" : " d") << ")" - << "{"; - - if (!inverse) - { - os << "using namespace " << db << ";" - << endl - << "statements_type& sts (*static_cast< statements_type* > (d));"; - - if (smart) - { - os << "cond_image_type& ci (sts.cond_image ());" - << endl; - - switch (ck) - { - case ck_ordered: - { - os << "init (ci, i);"; - break; - } - case ck_map: - case ck_multimap: - { - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - os << endl - << "if (sts.cond_binding_test_version ())" - << "{" - << "const binding& id (sts.id_binding ());" - << "bind (sts.cond_bind (), id.bind, id.count, ci);" - << "sts.cond_binding_update_version ();" - << "}"; - } - - os << "sts.delete_statement ().execute ();"; - } - - os << "}"; - - // persist - // - if (!inverse) - { - os << "void " << scope << "::" << endl - << "persist (const container_type& c," << endl - << "statements_type& sts"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << endl - << "functions_type& fs (sts.functions ());"; - - if (versioned) - os << "sts.version_migration (svm);"; - - if (!smart && ck == ck_ordered) - os << "fs.ordered_ = " << ordered << ";"; - - os << "container_traits_type::persist (c, fs);" - << "}"; - } - - // load - // - os << "void " << scope << "::" << endl - << "load (container_type& c," << endl - << "statements_type& sts"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << "using " << db << "::select_statement;" // Conflicts. - << endl - << "const binding& id (sts.id_binding ());" - << endl - << "if (sts.data_binding_test_version ())" - << "{" - << "bind (sts.data_bind (), id.bind, id.count, sts.data_image ()" << - (versioned ? ", svm" : "") << ");" - << "sts.data_binding_update_version ();" - << "}" - // We use the id binding directly so no need to check cond binding. - // - << "select_statement& st (sts.select_statement ());" - << "st.execute ();" - << "auto_result ar (st);"; - - // If we are loading eager object pointers, we may need to cache - // the result since we will be loading other objects. - // - if (eager_ptr) - cache_result ("st"); - - os << "select_statement::result r (st.fetch ());"; - - if (grow) - os << endl - << "if (r == select_statement::truncated)" - << "{" - << "data_image_type& di (sts.data_image ());" - << "grow (di, sts.select_image_truncated ()" << - (versioned ? ", svm" : "") << ");" - << endl - << "if (sts.data_binding_test_version ())" - << "{" - // Id cannot change. - // - << "bind (sts.data_bind (), 0, id.count, di" << - (versioned ? ", svm" : "") << ");" - << "sts.data_binding_update_version ();" - << "st.refetch ();" - << "}" - << "}"; - - os << "bool more (r != select_statement::no_data);" - << endl - << "functions_type& fs (sts.functions ());"; - - if (versioned) - os << "sts.version_migration (svm);"; - - if (!smart && ck == ck_ordered) - os << "fs.ordered_ = " << ordered << ";"; - - os << "container_traits_type::load (c, more, fs);" - << "}"; - - // update - // - if (!(inverse || readonly (member_path_, member_scope_))) - { - os << "void " << scope << "::" << endl - << "update (const container_type& c," << endl - << "statements_type& sts"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << endl - << "functions_type& fs (sts.functions ());"; - - if (versioned) - os << "sts.version_migration (svm);"; - - if (!smart && ck == ck_ordered) - os << "fs.ordered_ = " << ordered << ";"; - - os << "container_traits_type::update (c, fs);" - << "}"; - } - - // erase - // - if (!inverse) - { - os << "void " << scope << "::" << endl - << "erase ("; - - if (smart) - os << "const container_type* c, "; - - os << "statements_type& sts)" - << "{" - << "using namespace " << db << ";" - << endl - << "functions_type& fs (sts.functions ());"; - - if (!smart && ck == ck_ordered) - os << "fs.ordered_ = " << ordered << ";"; - - os << "container_traits_type::erase (" << (smart ? "c, " : "") << "fs);" - << "}"; - } - } - - protected: - string scope_; - semantics::class_& c_; - }; - - // Extra statement cache members for containers. - // - struct container_cache_members: object_members_base, virtual context - { - typedef container_cache_members base; - - container_cache_members () - : object_members_base (true, false, false) - { - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type& c) - { - bool smart (!context::inverse (m, "value") && - !unordered (m) && - container_smart (c)); - - string traits (flat_prefix_ + public_name (m) + "_traits"); - - os << db << "::" << (smart ? "smart_" : "") << - "container_statements_impl< " << traits << " > " << - flat_prefix_ << m.name () << ";"; - } - }; - - struct container_cache_init_members: object_members_base, virtual context - { - typedef container_cache_init_members base; - - container_cache_init_members () - : object_members_base (true, false, false), first_ (true) - { - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type&) - { - if (first_) - { - os << endl - << ": "; - first_ = false; - } - else - os << "," << endl - << " "; - - os << flat_prefix_ << m.name () << " (c, id"; - extra_members (); - os << ")"; - } - - virtual void - extra_members () {} - - protected: - bool first_; - }; - - // Extra statement cache members for sections. - // - struct section_cache_members: virtual context - { - typedef section_cache_members base; - - virtual void - traverse (user_section& s) - { - string traits (public_name (*s.member) + "_traits"); - - os << db << "::" << "section_statements< " << - class_fq_name (*s.object) << ", " << traits << " > " << - s.member->name () << ";"; - } - }; - - struct section_cache_init_members: virtual context - { - typedef section_cache_init_members base; - - section_cache_init_members (bool first): first_ (first) {} - - virtual void - traverse (user_section& s) - { - if (first_) - { - os << endl - << ": "; - first_ = false; - } - else - os << "," << endl - << " "; - - os << s.member->name () << " (c, im, idim, id, idv"; - extra_members (); - os << ")"; - } - - virtual void - extra_members () {} - - protected: - bool first_; - }; - - // Calls for container members. - // - struct container_calls: object_members_base, virtual context - { - typedef container_calls base; - - enum call_type - { - persist_call, - load_call, - update_call, - erase_obj_call, - erase_id_call, - section_call - }; - - container_calls (call_type call, object_section* section = 0) - : object_members_base (true, false, true, false, section), - call_ (call), - obj_prefix_ ("obj"), - by_value_ (0) - { - } - - virtual bool - section_test (data_member_path const& mp) - { - object_section& s (section (mp)); - - // Include eager loaded members into the main section for - // load calls. - // - return section_ == 0 || - *section_ == s || - (call_ == load_call && - *section_ == main_section && - !s.separate_load ()); - } - - virtual void - traverse_pointer (semantics::data_member&, semantics::class_&) - { - // We don't want to traverse composite id. - } - - virtual void - traverse_composite_wrapper (semantics::data_member* m, - semantics::class_& c, - semantics::type* w) - { - if (m == 0 || - call_ == erase_id_call || - (call_ == load_call && by_value_ != 0)) - { - object_members_base::traverse_composite (m, c); - return; - } - - // Get this member using the accessor expression. - // - member_access& ma ( - m->get (call_ == load_call ? "set" : "get")); - - // We don't support by-value modifiers for composite values - // with containers. However, at this point we don't know - // whether this composite value has any containers. So we - // are just going to set a flag that can be checked in - // traverse_container() below. - // - if (call_ == load_call && ma.placeholder ()) - { - by_value_ = &ma; - object_members_base::traverse_composite (m, c); - by_value_ = 0; - return; - } - - // We also don't support by-value accessors is there is a - // smart container inside (which, again, we don't know at - // this point). So keep track of such first instance. - // - member_access* old_by_value (by_value_); - if (call_ != load_call && ma.by_value && by_value_ == 0) - by_value_ = &ma; - - string old_op (obj_prefix_); - string old_f (from_); - obj_prefix_.clear (); - - // If this member is const and we have a synthesized direct - // access, then cast away constness. Otherwise, we assume - // that the user-provided expression handles this. - // - bool cast (call_ == load_call && ma.direct () && const_member (*m)); - if (cast) - obj_prefix_ = "const_cast< " + member_ref_type (*m, false) + - " > (\n"; - - obj_prefix_ += ma.translate (old_op); - - if (cast) - obj_prefix_ += ")"; - - // If this is not a synthesized expression, then store its - // location which we will output later for easier error - // tracking. - // - if (!ma.synthesized) - from_ += "// From " + location_string (ma.loc, true) + "\n"; - - // If this is a wrapped composite value, then we need to "unwrap" it. - // - if (w != 0) - { - semantics::names* hint; - semantics::type& t (utype (*m, hint)); - - // Because we cannot have nested containers, member type should - // be the same as w. - // - assert (&t == w); - - obj_prefix_ = "wrapper_traits< " + t.fq_name (hint) + " >::" + - (call_ == load_call ? "set_ref" : "get_ref") + - " (\n" + obj_prefix_ + ")"; - } - - object_members_base::traverse_composite (m, c); - from_ = old_f; - obj_prefix_ = old_op; - by_value_ = old_by_value; - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type& c) - { - using semantics::type; - - bool inverse (context::inverse (m, "value")); - bool smart (!inverse && !unordered (m) && container_smart (c)); - bool versioned (context::versioned (m)); - - // In certain cases we don't need to do anything. - // - if ((call_ != load_call && inverse) || - (call_ == section_call && !smart) || - (call_ == update_call && readonly (member_path_, member_scope_))) - return; - - string const& name (m.name ()); - string sts_name (flat_prefix_ + name); - string traits (flat_prefix_ + public_name (m) + "_traits"); - - os << "// " << member_prefix_ << m.name () << endl - << "//" << endl; - - // Get this member using the accessor expression. - // - string var; - member_access& ma ( - m.get (call_ == load_call ? "set" : "get")); - - // We don't support by-value modifiers for composite values - // with containers. - // - if (call_ == load_call && by_value_ != 0) - { - error (by_value_->loc) << "by-value modification of a composite " - << "value with container is not supported" - << endl; - info (m.location ()) << "container member is defined here" << endl; - throw operation_failed (); - } - - // We don't support by-value accessors for smart containers. - // - if (call_ != load_call && smart) - { - if (by_value_ != 0) - { - error (by_value_->loc) << "by-value access to a composite value " - << "with smart container is not supported" - << endl; - info (m.location ()) << "container member is defined here" << endl; - throw operation_failed (); - } - - if (ma.by_value) - { - error (ma.loc) << "by-value access to a smart container is not " - << "supported" << endl; - info (m.location ()) << "container member is defined here" << endl; - throw operation_failed (); - } - } - - // If the member is soft- added or deleted, check the version. - // - unsigned long long av (added (member_path_)); - unsigned long long dv (deleted (member_path_)); - - // If the addition/deletion version is the same as the section's, - // then we don't need the test. - // - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - 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; - } - - os << "{"; - - if (call_ != erase_id_call && (call_ != erase_obj_call || smart)) - { - // See if we are modifying via a reference or proper modifier. - // - if (call_ == load_call && ma.placeholder ()) - os << member_val_type (m, false, "v") << ";" - << endl; - else - { - // Note: this case is for both access and modification. - // - - // Output stored locations, if any. - // - os << from_; - - // If this is not a synthesized expression, then output its - // location for easier error tracking. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - // Note that here we don't decay arrays. - // - const string& ref_type ( - member_ref_type (m, call_ != load_call, "v", false /* decay */)); - - // VC++ cannot grok the constructor syntax. - // - os << ref_type << " =" << endl - << " "; - - // If this member is const and we have a synthesized direct - // access, then cast away constness. Otherwise, we assume - // that the user-provided expression handles this. - // - bool cast (call_ == load_call && ma.direct () && const_member (m)); - if (cast) - os << "const_cast< " << member_ref_type (m, false, "", false) << - " > (" << endl; - - os << ma.translate (obj_prefix_); - - if (cast) - os << ")"; - - os << ";" - << endl; - } - - var = "v"; - - semantics::names* hint; - semantics::type& t (utype (m, hint)); - - // If this is a wrapped container, then we need to "unwrap" it. - // - if (wrapper (t)) - { - var = "wrapper_traits< " + t.fq_name (hint) + " >::" + - (call_ == load_call ? "set_ref" : "get_ref") + " (" + var + ")"; - } - } - - switch (call_) - { - case persist_call: - { - os << traits << "::persist (" << endl - << var << "," << endl - << "esc." << sts_name; - - if (versioned) - os << "," << endl - << "svm"; - - os << ");"; - break; - } - case load_call: - { - os << traits << "::load (" << endl - << var << "," << endl - << "esc." << sts_name; - - if (versioned) - os << "," << endl - << "svm"; - - os << ");"; - break; - } - case update_call: - { - os << traits << "::update (" << endl - << var << "," << endl - << "esc." << sts_name; - - if (versioned) - os << "," << endl - << "svm"; - - os << ");"; - break; - } - case erase_obj_call: - { - os << traits << "::erase (" << endl; - - if (smart) - os << "&" << var << "," << endl; - - os << "esc." << sts_name << ");" - << endl; - break; - } - case erase_id_call: - { - os << traits << "::erase (" << endl; - - if (smart) - os << "0," << endl; - - os << "esc." << sts_name << ");" - << endl; - break; - } - case section_call: - { - os << "if (" << traits << "::container_traits_type::changed (" << - var << "))" << endl - << "s.reset (true, true);"; // loaded, changed - break; - } - } - - if (call_ == load_call) - { - // Call the modifier if we are using a proper one. - // - if (ma.placeholder ()) - { - os << endl - << from_; - - // If this is not a synthesized expression, then output its - // location for easier error tracking. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - os << ma.translate ( - obj_prefix_, "v", "static_cast<" + db.string () + - "::database&> (db)") << ";"; - } - } - - os << "}"; - } - - protected: - call_type call_; - string obj_prefix_; - string from_; - member_access* by_value_; - }; - - // - // - struct section_traits: traversal::class_, virtual context - { - typedef section_traits base; - - section_traits (semantics::class_& c) - : c_ (c), - scope_ ("access::object_traits_impl< " + class_fq_name (c) + - ", id_" + db.string () + " >") - { - } - - // Additional code that need to be executed following the call to - // init_value(). - // - virtual void - init_value_extra () - { - } - - virtual void - process_statement_columns (statement_columns&, - statement_kind, - bool /*dynamic*/) - { - } - - virtual void - section_extra (user_section&) - { - } - - // Returning "1" means increment by one. - // - virtual string - optimistic_version_increment (semantics::data_member&) - { - return "1"; - } - - virtual string - update_statement_extra (user_section&) - { - return ""; - } - - virtual void - traverse (user_section& s) - { - using semantics::class_; - using semantics::data_member; - - data_member& m (*s.member); - - class_* poly_root (polymorphic (c_)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c_); - class_* poly_base (poly_derived ? &polymorphic_base (c_) : 0); - - data_member* opt (optimistic (c_)); - - // Treat the special version update sections as abstract in reuse - // inheritance. - // - bool reuse_abst (!poly && - (abstract (c_) || - s.special == user_section::special_version)); - - bool load (s.total != 0 && s.separate_load ()); - bool load_con (s.containers && s.separate_load ()); - bool load_opt (s.optimistic () && s.separate_load ()); - - bool update (s.total != s.inverse + s.readonly); // Always separate. - bool update_con (s.readwrite_containers); - bool update_opt (s.optimistic () && (s.readwrite_containers || poly)); - - // Don't generate anything for empty sections. - // - if (!(load || load_con || load_opt || - update || update_con || update_opt)) - return; - - // If we are adding a new section to a derived class in an optimistic - // polymorphic hierarchy, then pretend it inherits from the special - // version update section. - // - user_section* rs (0); - if (opt != 0) - { - // Skip overrides and get to the new section if polymorphic. - // - for (rs = &s; poly && rs->base != 0; rs = rs->base) ; - - if (rs != 0) - { - if (rs->object != &opt->scope ()) - rs->base = &(poly ? poly_root : &opt->scope ())-> - get ("user-sections").back (); - else - rs = 0; - } - } - - string name (public_name (m) + "_traits"); - string scope (scope_ + "::" + name); - - os << "// " << m.name () << endl - << "//" << endl - << endl; - - // bind (id, image_type) - // - if (load || load_opt || update || update_opt) - { - os << "std::size_t " << scope << "::" << endl - << "bind (" << bind_vector << " b," << endl - << "const " << bind_vector << (reuse_abst ? "," : " id,") << endl - << "std::size_t" << (reuse_abst ? "," : " id_size,") << endl - << "image_type& i," << endl - << db << "::statement_kind sk"; - - if (s.versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (sk);"; - - if (s.versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "using namespace " << db << ";" - << endl - << "std::size_t n (0);" - << endl; - - // Bind reuse base. It is always first and we never ask it - // to bind id(+ver). - // - if (s.base != 0 && !poly_derived) - { - user_section& b (*s.base); - - bool load (b.total != 0 && b.separate_load ()); - bool load_opt (b.optimistic () && b.separate_load ()); - - bool update (b.total != b.inverse + b.readonly); - - if (load || load_opt || update) - os << "// " << class_name (*b.object) << endl - << "//" << endl - << "n += object_traits_impl< " << class_fq_name (*b.object) << - ", id_" << db << " >::" << public_name (*b.member) << - "_traits::bind (" << endl - << "b, 0, 0, i, sk" << (b.versioned ? ", svm" : "") << ");" - << endl; - } - - // Bind members. - // - { - instance bm ("", "", &s); - traversal::names n (*bm); - names (c_, n); - } - - // Bind polymorphic image chain for the select statement. - // - if (s.base != 0 && poly_derived && s.separate_load ()) - { - // Find the next base that has something to load, if any. - // - user_section* b (s.base); - string acc (".base"); - for (class_* bo (poly_base);; bo = &polymorphic_base (*bo)) - { - if (b->object == bo) - { - if (b->total != 0 || b->optimistic ()) - break; - - b = b->base; - if (b == 0 || !polymorphic (*b->object)) - { - b = 0; - break; - } - } - acc += "->base"; - } - - if (b != 0) - os << "// " << class_name (*b->object) << endl - << "//" << endl - << "if (sk == statement_select)" << endl - << "n += object_traits_impl< " << class_fq_name (*b->object) << - ", id_" << db << " >::" << public_name (*b->member) << - "_traits::bind (" << endl - << "b + n, 0, 0, *i" << acc << ", sk" << - (b->versioned ? ", svm" : "") << ");" - << endl; - } - - if (!reuse_abst) - os << "// object_id" << endl - << "//" << endl - << "if (id != 0)" << endl - << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));" - << "n += id_size;" // Not in if for "id unchanged" optimization. - << endl; - - os << "return n;" - << "}"; - } - - // grow () - // - if (generate_grow && (load || load_opt)) - { - os << "bool " << scope << "::" << endl - << "grow (image_type& i," << endl - << truncated_vector << " t"; - - if (s.versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (t);"; - - if (s.versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "bool grew (false);" - << endl; - - size_t index (0); - - if (s.base != 0 && !poly_derived) - { - user_section& b (*s.base); - - bool load (b.total != 0); - bool load_opt (b.optimistic ()); - - if (load || load_opt) - { - os << "// " << class_name (*b.object) << endl - << "//" << endl - << "grew = object_traits_impl< " << class_fq_name (*b.object) << - ", id_" << db << " >::" << public_name (*b.member) << - "_traits::grow (i, t" << (b.versioned ? ", svm" : "") << ");" - << endl; - - index += b.total + (load_opt ? 1 : 0); - } - } - - { - user_section* ps (&s); - instance gm (index, "", ps); - traversal::names n (*gm); - names (c_, n); - } - - // Grow polymorphic image chain. - // - if (s.base != 0 && poly_derived) - { - // Find the next base that has something to load, if any. - // - user_section* b (s.base); - string acc (".base"); - size_t cols; - for (class_* bo (poly_base);; bo = &polymorphic_base (*bo)) - { - if (b->object == bo) - { - cols = b->total + (b->optimistic () ? 1 : 0); - if (cols != 0) - break; - - b = b->base; - if (b == 0 || !polymorphic (*b->object)) - { - b = 0; - break; - } - } - acc += "->base"; - } - - if (b != 0) - os << "// " << class_name (*b->object) << endl - << "//" << endl - << "if (object_traits_impl< " << class_fq_name (*b->object) << - ", id_" << db << " >::" << public_name (*b->member) << - "_traits::grow (" << endl - << "*i" << acc << ", t + " << cols << "UL" << - (b->versioned ? ", svm" : "") << "))" << endl - << "i" << acc << "->version++;" - << endl; - } - - os << "return grew;" << endl - << "}"; - } - - // init (object, image) - // - if (load) - { - os << "void " << scope << "::" << endl - << "init (object_type& o," << endl - << "const image_type& i," << endl - << "database* db"; - - if (s.versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (db);"; - - if (s.versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl; - - if (s.base != 0) - { - if (!poly_derived) - { - user_section& b (*s.base); - - bool load (b.total != 0); - - if (load) - os << "// " << class_name (*b.object) << endl - << "//" << endl - << "object_traits_impl< " << class_fq_name (*b.object) << - ", id_" << db << " >::" << public_name (*b.member) << - "_traits::init (o, i, db" << - (b.versioned ? ", svm" : "") << ");" - << endl; - } - else - { - // Find the next base that has something to load, if any. - // - user_section* b (s.base); - string acc (".base"); - for (class_* bo (poly_base);; bo = &polymorphic_base (*bo)) - { - if (b->object == bo) - { - if (b->total != 0) - break; - - b = b->base; - if (b == 0 || !polymorphic (*b->object)) - { - b = 0; - break; - } - } - acc += "->base"; - } - - if (b != 0) - os << "// " << class_name (*b->object) << endl - << "//" << endl - << "object_traits_impl< " << class_fq_name (*b->object) << - ", id_" << db << " >::" << public_name (*b->member) << - "_traits::init (" << endl - << "o, *i" << acc << ", db" << - (b->versioned ? ", svm" : "") << ");" - << endl; - } - } - - { - instance iv ("", "", true, &s); - traversal::names n (*iv); - names (c_, n); - } - - os << "}"; - } - - // init (image, object) - // - if (update) - { - os << (generate_grow ? "bool " : "void ") << scope << "::" << endl - << "init (image_type& i," << endl - << "const object_type& o"; - - if (s.versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{"; - - if (s.versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);" - << endl; - - os << "using namespace " << db << ";" - << endl - << "statement_kind sk (statement_insert);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl; - - // There is no call to init_image_pre() here (which calls the - // copy callback for some databases) since we are not going to - // touch any of the members that were loaded by query. - - if (generate_grow) - os << "bool grew (false);" - << endl; - - if (s.base != 0 && !poly_derived) - { - user_section& b (*s.base); - - bool update (b.total != b.inverse + b.readonly); - - if (update) - os << "// " << class_name (*b.object) << endl - << "//" << endl - << (generate_grow ? "grew = " : "") << - "object_traits_impl< " << class_fq_name (*b.object) << - ", id_" << db << " >::" << public_name (*b.member) << - "_traits::init (i, o" << (b.versioned ? ", svm" : "") << ");" - << endl; - } - - { - instance ii ("", "", &s); - traversal::names n (*ii); - names (c_, n); - } - - if (generate_grow) - os << "return grew;"; - - os << "}"; - } - - // The rest does not apply to reuse-abstract sections. - // - if (reuse_abst) - { - section_extra (s); - return; - } - - string sep (s.versioned ? "\n" : " "); - - // Schema name as a string literal or empty. - // - string schema_name (options.schema_name ()[db]); - if (!schema_name.empty ()) - schema_name = strlit (schema_name); - - // Statements. - // - qname table (table_name (c_)); - string qtable (quote_id (table)); - - instance id_cols; - id_cols->traverse (*id_member (c_)); - - // select_statement - // - if (load || load_opt) - { - size_t depth (poly_derived ? polymorphic_depth (c_) : 1); - - statement_columns sc; - { - statement_kind sk (statement_select); // Imperfect forwarding. - object_section* ps (&s); // Imperfect forwarding. - instance t (qtable, sk, sc, depth, ps); - t->traverse (c_); - process_statement_columns (sc, statement_select, s.versioned); - } - - os << "const char " << scope << "::" << endl - << "select_statement[] =" << endl - << strlit ("SELECT" + sep) << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - os << strlit ("FROM " + qtable + sep) << endl; - - // Join polymorphic bases. - // - if (depth != 1 && s.base != 0) - { - bool f (false); //@@ (im)perfect forwarding - size_t d (depth - 1); //@@ (im)perfect forward. - instance j (c_, f, d, "", s.base); - j->traverse (*poly_base); - - for (strings::const_iterator i (j->begin ()); i != j->end (); ++i) - os << strlit (*i + sep) << endl; - } - - // Join tables of inverse members belonging to this section. - // - { - bool f (false); // @@ (im)perfect forwarding - object_section* ps (&s); // @@ (im)perfect forwarding - instance j (c_, f, depth, ps); - j->traverse (c_); - - for (strings::const_iterator i (j->begin ()); i != j->end (); ++i) - os << strlit (*i + sep) << endl; - } - - string where ("WHERE "); - instance qp (statement_select, table); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - os << strlit (where) << ";" - << endl; - } - - // update_statement - // - if (update || update_opt) - { - instance qp (statement_update, table); - - statement_columns sc; - { - query_parameters* p (qp.get ()); // Imperfect forwarding. - statement_kind sk (statement_update); // Imperfect forwarding. - object_section* ps (&s); // Imperfect forwarding. - instance t (sk, sc, p, ps); - t->traverse (c_); - process_statement_columns (sc, statement_update, s.versioned); - } - - os << "const char " << scope << "::" << endl - << "update_statement[] =" << endl - << strlit ("UPDATE " + qtable + sep) << endl - << strlit ("SET" + sep) << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - // This didn't work out: cannot change the identity column. - // - //if (sc.empty ()) - //{ - // // We can end up with nothing to set if we need to "touch" a row - // // in order to increment its optimistic concurrency version. In - // // this case just do a dummy assignment based on the id column. - // // - // string const& c (quote_id (id_cols->begin ()->name)); - // os << strlit (c + "=" + c) << endl; - //} - - string extra (update_statement_extra (s)); - - if (!extra.empty ()) - os << strlit (extra + sep) << endl; - - string where ("WHERE "); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - if (s.optimistic ()) // Note: not update_opt. - { - string name (column_qname (*opt, column_prefix ())); - string type (column_type (*opt)); - - where += " AND " + name + "=" + - convert_to (qp->next (*opt, name, type), type, *opt); - } - - os << strlit (where) << ";" - << endl; - } - - // load () - // - if (load || load_opt || load_con) - { - os << "void " << scope << "::" << endl - << "load (extra_statement_cache_type& esc, object_type& obj" << - (poly ? ", bool top" : "") << ")" - << "{"; - - if (poly) - os << "ODB_POTENTIALLY_UNUSED (top);" - << endl; - - if (s.versioned || s.versioned_containers) - os << "const schema_version_migration& svm (" << endl - << "esc." << m.name () << ".version_migration (" << - schema_name << "));" - << endl; - - // Load values, if any. - // - if (load || load_opt) - { - // The SELECT statement for the top override loads all the - // values. - // - if (poly) - os << "if (top)" - << "{"; - - // Note that we don't use delayed load machinery here. While - // a section can definitely contain self-referencing pointers, - // loading such a pointer won't mess up the data members in the - // image that we care about. It also holds true for streaming - // result, since the bindings are different. - - os << "using namespace " << db << ";" - << "using " << db << "::select_statement;" // Conflicts. - << endl - << "statements_type& sts (esc." << m.name () << ");" - << endl - << "image_type& im (sts.image ());" - << "binding& imb (sts.select_image_binding ());" - << endl; - - // For the polymorphic case, instead of storing an array of - // versions as we do for objects, we will add all the versions - // up and use that as a cumulative image chain version. If you - // meditate a bit on that, you will realize that it will work - // (hint: versions can only increase). - // - string ver; - string ver_decl; - - if (s.base != 0 && poly_derived) - { - ver = "imv"; - ver_decl = "std::size_t imv (im.version"; - - user_section* b (s.base); - string acc ("im.base"); - for (class_* bo (poly_base);; bo = &polymorphic_base (*bo)) - { - if (b->object == bo) - { - if (b->total != 0 || b->optimistic ()) - ver_decl += " +\n" + acc + "->version"; - - b = b->base; - if (b == 0 || !polymorphic (*b->object)) - { - b = 0; - break; - } - } - acc += "->base"; - } - - ver_decl += ")"; - - os << ver_decl << ";" - << endl; - } - else - ver = "im.version"; - - os << "if (" << ver << " != sts.select_image_version () ||" << endl - << "imb.version == 0)" - << "{" - << "bind (imb.bind, 0, 0, im, statement_select" << - (s.versioned ? ", svm" : "") << ");" - << "sts.select_image_version (" << ver << ");" - << "imb.version++;" - << "}"; - - // Id binding is assumed initialized and bound. - // - os << "select_statement& st (sts.select_statement ());"; - - // The statement can be dynamically empty. - // - if (s.versioned) - os << "if (!st.empty ())" - << "{"; - - os << "st.execute ();" - << "auto_result ar (st);" - << "select_statement::result r (st.fetch ());" - << endl; - - os << "if (r == select_statement::no_data)" << endl - << "throw object_not_persistent ();" - << endl; - - if (grow (c_, &s)) - { - os << "if (r == select_statement::truncated)" - << "{" - << "if (grow (im, sts.select_image_truncated ()" << - (s.versioned ? ", svm" : "") << "))" << endl - << "im.version++;" - << endl; - - // The same logic as above. - // - if (s.base != 0 && poly_derived) - os << ver_decl << ";" - << endl; - - os << "if (" << ver << " != sts.select_image_version ())" - << "{" - << "bind (imb.bind, 0, 0, im, statement_select" << - (s.versioned ? ", svm" : "") << ");" - << "sts.select_image_version (" << ver << ");" - << "imb.version++;" - << "st.refetch ();" - << "}" - << "}"; - } - - if (opt != 0) // Not load_opt, we do it in poly-derived as well. - { - os << "if ("; - - if (poly_derived) - { - os << "root_traits::version (*im.base"; - for (class_* b (poly_base); - b != poly_root; - b = &polymorphic_base (*b)) - os << "->base"; - os << ")"; - } - else - os << "version (im)"; - - os << " != " << (poly_derived ? "root_traits::" : "") << - "version (obj))" << endl - << "throw object_changed ();" - << endl; - } - - if (load) - { - os << "init (obj, im, &sts.connection ().database ()" << - (s.versioned ? ", svm" : "") << ");"; - init_value_extra (); // Stream results, etc. - os << endl; - } - - if (s.versioned) - os << "}"; // if (!st.empty ()) - - if (poly) - os << "}"; // if (top) - } - - // Call base to load its containers, if this is an override. - // - if (poly_derived && s.base != 0) - { - user_section* b (s.base); - for (class_* bo (poly_base);; bo = &polymorphic_base (*bo)) - { - if (b->object == bo) - { - // If we don't have any values of our own but out base - // does, then allow it to load them. - // - if (b->containers || - (!load && (b->total != 0 || b->optimistic ()))) - break; - - b = b->base; - if (b == 0 || !polymorphic (*b->object)) - { - b = 0; - break; - } - } - } - - // This one is tricky: ideally we would do a direct call to - // the base's load() (which may not be our immediate base, - // BTW) but there is no easy way to resolve base's extra - // statements from ours. So, instead, we are going to go - // via the dispatch machinery which requires a connection - // rather than statements. Not the most efficient way but - // simple. - - // Find the "previous" override by starting the search from - // our base. - // - if (b != 0) - { - // Note that here we are using the base section index to - // handle the special version update base. - // - os << "info.base->find_section_load (" << b->index << "UL) (" << - "esc." << m.name () << ".connection (), obj, " << - // If we don't have any values of our own, then allow the - // base load its. - // - (load ? "false" : "top") << ");" - << endl; - } - } - - // Load our containers, if any. - // - if (s.containers) - { - instance t (container_calls::load_call, &s); - t->traverse (c_); - } - - os << "}"; - } - - // update () - // - if (update || update_opt || update_con) - { - os << "void " << scope << "::" << endl - << "update (extra_statement_cache_type& esc, " << - "const object_type& obj" << - (poly_derived && s.base != 0 ? ", bool base" : "") << ")" - << "{"; - - // Call base if this is an override. - // - if (poly_derived && s.base != 0) - { - user_section* b (s.base); - for (class_* bo (poly_base);; bo = &polymorphic_base (*bo)) - { - if (b->object == bo) - { - if (b->total != b->inverse + b->readonly || - b->readwrite_containers || - (poly && b->optimistic ())) - break; - - b = b->base; - if (b == 0 || !polymorphic (*b->object)) - { - b = 0; - break; - } - } - } - - // The same (tricky) logic as in load(). Note that here we are - // using the base section index to handle the special version - // update base. - // - if (b != 0) - os << "if (base)" << endl - << "info.base->find_section_update (" << b->index << - "UL) (esc." << m.name () << ".connection (), obj);" - << endl; - else - os << "ODB_POTENTIALLY_UNUSED (base);" - << endl; - } - - if (s.versioned || s.readwrite_versioned_containers) - os << "const schema_version_migration& svm (" << endl - << "esc." << m.name () << ".version_migration (" << - schema_name << "));" - << endl; - - // Update values, if any. - // - if (update || update_opt) - { - os << "using namespace " << db << ";" - << "using " << db << "::update_statement;" // Conflicts. - << endl - << "statements_type& sts (esc." << m.name () << ");" - << endl - << "image_type& im (sts.image ());" - << "const binding& id (sts.idv_binding ());" // id+version - << "binding& imb (sts.update_image_binding ());" - << endl; - - if (update) - { - if (generate_grow) - os << "if ("; - - os << "init (im, obj" << (s.versioned ? ", svm" : "") << ")"; - - if (generate_grow) - os << ")" << endl - << "im.version++"; - - os << ";" - << endl; - } - - os << "if (im.version != sts.update_image_version () ||" << endl - << "id.version != sts.update_id_binding_version () ||" << endl - << "imb.version == 0)" - << "{" - << "bind (imb.bind, id.bind, id.count, im, statement_update" << - (s.versioned ? ", svm" : "") << ");" - << "sts.update_image_version (im.version);" - << "sts.update_id_binding_version (id.version);" - << "imb.version++;" - << "}"; - - os << "update_statement& st (sts.update_statement ());" - << "if ("; - - if (s.versioned) - os << "!st.empty () && "; - - os << "st.execute () == 0)" << endl; - - if (opt == 0) - os << "throw object_not_persistent ();"; - else - os << "throw object_changed ();"; - - os << endl; - } - - // Update readwrite containers if any. - // - if (s.readwrite_containers) - { - instance t (container_calls::update_call, &s); - t->traverse (c_); - } - - // Update the optimistic concurrency version in the object member. - // Very similar code to object. - // - if (s.optimistic ()) // Note: not update_opt. - { - // Object is passed as const reference so we need to cast away - // constness. - // - const char* obj ("const_cast (obj)"); - string inc (optimistic_version_increment (*opt)); - - if (inc == "1") - inc_member (*opt, obj, "obj", "version_type"); - else - set_member (*opt, obj, inc, "", "version_type"); - } - - os << "}"; - } - - section_extra (s); - - if (rs != 0) - rs->base = 0; - } - - using class_::traverse; // Unhide. - - protected: - semantics::class_& c_; - string scope_; - }; - - // Output a list of parameters for the persist statement. - // - struct persist_statement_params: object_columns_base, virtual context - { - typedef persist_statement_params base; - - persist_statement_params (string& params, - query_parameters& qp, - const string& sep) - : params_ (params), qp_ (qp), sep_ (sep) - { - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - if (!inverse (m, key_prefix_)) - object_columns_base::traverse_pointer (m, c); - } - - virtual bool - traverse_column (semantics::data_member& m, - string const& name, - bool first) - { - string p; - - if (version (m)) - p = version_value (m); - else - { - const string& qname (quote_id (name)); - const string& type (column_type ()); - - p = auto_ (m) // Only simple, direct id can be auto. - ? qp_.auto_id (m, qname, type) - : qp_.next (m, qname, type); - } - - if (!p.empty ()) - { - if (!first) - { - params_ += ','; - params_ += sep_; - } - - params_ += (p != "DEFAULT" ? convert_to (p, column_type (), m) : p); - } - - return !p.empty (); - } - - virtual string - version_value (semantics::data_member&) - { - return "1"; - } - - private: - string& params_; - query_parameters& qp_; - const string& sep_; - }; - - // - // - struct class_: traversal::class_, virtual context - { - typedef class_ base; - - class_ () - : typedefs_ (false), - query_columns_type_ (false, false, false), - view_query_columns_type_ (false), - index_ (0), - grow_base_ (index_), - grow_member_ (index_), - grow_version_member_ (index_, "version_"), - grow_discriminator_member_ (index_, "discriminator_"), - bind_id_member_ ("id_"), - bind_version_member_ ("version_"), - bind_discriminator_member_ ("discriminator_"), - init_id_image_member_ ("id_", "id"), - init_version_image_member_ ("version_", "(*v)"), - init_view_pointer_member_pre_ (true, *init_value_member_), - init_view_pointer_member_post_ (false, *init_value_member_), - init_id_value_member_ ("id"), - init_id_value_member_id_image_ ("id", "id_"), - init_version_value_member_ ("v"), - init_named_version_value_member_ ("v", "version_"), - init_discriminator_value_member_ ("d", "", false), - init_named_discriminator_value_member_ ( - "d", "discriminator_", false) - { - init (); - } - - class_ (class_ const&) - : root_context (), //@@ -Wextra - context (), - typedefs_ (false), - query_columns_type_ (false, false, false), - view_query_columns_type_ (false), - index_ (0), - grow_base_ (index_), - grow_member_ (index_), - grow_version_member_ (index_, "version_"), - grow_discriminator_member_ (index_, "discriminator_"), - bind_id_member_ ("id_"), - bind_version_member_ ("version_"), - bind_discriminator_member_ ("discriminator_"), - init_id_image_member_ ("id_", "id"), - init_version_image_member_ ("version_", "(*v)"), - init_view_pointer_member_pre_ (true, *init_value_member_), - init_view_pointer_member_post_ (false, *init_value_member_), - init_id_value_member_ ("id"), - init_id_value_member_id_image_ ("id", "id_"), - init_version_value_member_ ("v"), - init_named_version_value_member_ ("v", "version_"), - init_discriminator_value_member_ ("d", "", false), - init_named_discriminator_value_member_ ( - "d", "discriminator_", false) - { - init (); - } - - void - init () - { - *this >> defines_ >> *this; - *this >> typedefs_ >> *this; - - if (generate_grow) - { - grow_base_inherits_ >> grow_base_; - grow_member_names_ >> grow_member_; - } - - bind_base_inherits_ >> bind_base_; - bind_member_names_ >> bind_member_; - - init_image_base_inherits_ >> init_image_base_; - init_image_member_names_ >> init_image_member_; - - init_value_base_inherits_ >> init_value_base_; - init_value_member_names_ >> init_value_member_; - - init_view_pointer_member_pre_names_ >> init_view_pointer_member_pre_; - init_view_pointer_member_post_names_ >> init_view_pointer_member_post_; - } - - virtual void - init_auto_id (semantics::data_member&, // id member - string const&) // image variable prefix - { - if (insert_send_auto_id) - assert (false); - } - - virtual void - init_image_pre (type&) - { - } - - virtual void - init_value_extra () - { - } - - 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; - } - - // - // statements - // - - enum persist_position - { - persist_after_columns, - persist_after_values - }; - - virtual string - persist_statement_extra (type&, query_parameters&, persist_position) - { - return ""; - } - - virtual string - update_statement_extra (type&) - { - return ""; - } - - // - // common - // - - virtual void - post_query_ (type&, bool /*once_off*/) - { - } - - virtual void - process_statement_columns (statement_columns&, - statement_kind, - bool /*dynamic*/) - { - } - - // - // object - // - - virtual void - object_extra (type&) {} - - virtual void - extra_statement_cache_extra_args (bool /*containers*/, - bool /*sections*/) {} - - virtual void - object_query_statement_ctor_args (type&, - std::string const& q, - bool process, - bool /*prepared*/) - { - os << "conn," << endl - << "text," << endl - << process << "," << endl // Process. - << "true," << endl // Optimize. - << q << ".parameters_binding ()," << endl - << "imb"; - } - - virtual void - object_erase_query_statement_ctor_args (type&) - { - os << "conn," << endl - << "text," << endl - << "q.parameters_binding ()"; - } - - virtual string - optimistic_version_init (semantics::data_member&, bool /*index*/ = false) - { - return "1"; - } - - // Returning "1" means increment by one. - // - virtual string - optimistic_version_increment (semantics::data_member&, - bool /*index*/ = false) - { - return "1"; - } - - virtual bool - optimistic_insert_bind_version (semantics::data_member&) - { - return false; - } - - virtual void - traverse_object (type& c); - - // - // view - // - - virtual void - view_extra (type&) - { - } - - virtual void - view_query_statement_ctor_args (type&, - string const& q, - bool process, - bool /*prepared*/) - { - os << "conn," << endl - << q << ".clause ()," << endl - << process << "," << endl // Process. - << "true," << endl // Optimize. - << q << ".parameters_binding ()," << endl - << "imb"; - } - - virtual string - from_trailer (type&) { return "";} - - virtual string - select_trailer (type& c) - { - return c.get ("query").for_update ? "FOR UPDATE" : ""; - } - - virtual string - join_syntax (view_object const& vo) - { - const char* r (0); - - switch (vo.join) - { - case view_object::left: r = "LEFT JOIN"; break; - case view_object::right: r = "RIGHT JOIN"; break; - case view_object::full: r = "FULL JOIN"; break; - case view_object::inner: r = "INNER JOIN"; break; - case view_object::cross: r = "CROSS JOIN"; break; - } - - return r; - } - - virtual void - traverse_view (type& c); - - struct expression - { - explicit - expression (std::string const& v): kind (literal), value (v) {} - expression (view_object* vo): kind (pointer), vo (vo) {} - - enum kind_type {literal, pointer}; - - kind_type kind; - std::string value; - data_member_path member_path; - view_object* vo; - }; - - expression - translate_expression (type& c, - cxx_tokens const&, - semantics::scope& start_scope, - location_t loc, - string const& prag, - bool* placeholder = 0, - bool predicate = true); - // - // composite - // - - 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; - - // Containers. - // - { - instance t (c); - t->traverse (c); - } - - // grow () - // - if (generate_grow) - { - os << "bool " << traits << "::" << endl - << "grow (image_type& i," << endl - << truncated_vector << " t"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (t);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "bool grew (false);" - << endl; - - index_ = 0; - inherits (c, grow_base_inherits_); - names (c, grow_member_names_); - - os << "return grew;" - << "}"; - } - - // bind (image_type) - // - os << "void " << traits << "::" << endl - << "bind (" << bind_vector << " b," << endl - << "image_type& i," << endl - << db << "::statement_kind sk"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (b);" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (sk);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "using namespace " << db << ";" - << endl; - - if (readonly (c)) - os << "assert (sk != statement_update);" - << endl; - - os << "std::size_t n (0);" - << "ODB_POTENTIALLY_UNUSED (n);" - << endl; - - inherits (c, bind_base_inherits_); - names (c, bind_member_names_); - - os << "}"; - - // init (image, value) - // - os << (generate_grow ? "bool " : "void ") << traits << "::" << endl - << "init (image_type& i," << endl - << "const value_type& o," << endl - << db << "::statement_kind sk"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (o);" - << "ODB_POTENTIALLY_UNUSED (sk);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "using namespace " << db << ";" - << endl; - - if (readonly (c)) - os << "assert (sk != statement_update);" - << endl; - - if (generate_grow) - os << "bool grew (false);" - << endl; - - inherits (c, init_image_base_inherits_); - names (c, init_image_member_names_); - - if (generate_grow) - os << "return grew;"; - - os << "}"; - - // init (value, image) - // - os << "void " << traits << "::" << endl - << "init (value_type& o," << endl - << "const image_type& i," << endl - << "database* db"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (o);" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (db);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl; - - inherits (c, init_value_base_inherits_); - names (c, init_value_member_names_); - - os << "}"; - } - - private: - traversal::defines defines_; - typedefs typedefs_; - - instance query_columns_type_; - instance view_query_columns_type_; - - size_t index_; - instance grow_base_; - traversal::inherits grow_base_inherits_; - instance grow_member_; - traversal::names grow_member_names_; - instance grow_version_member_; - instance grow_discriminator_member_; - - - instance bind_base_; - traversal::inherits bind_base_inherits_; - instance bind_member_; - traversal::names bind_member_names_; - instance bind_id_member_; - instance bind_version_member_; - instance bind_discriminator_member_; - - instance init_image_base_; - traversal::inherits init_image_base_inherits_; - instance init_image_member_; - traversal::names init_image_member_names_; - - instance init_id_image_member_; - instance init_version_image_member_; - - instance init_value_base_; - traversal::inherits init_value_base_inherits_; - instance init_value_member_; - traversal::names init_value_member_names_; - - instance init_view_pointer_member_pre_; - instance init_view_pointer_member_post_; - traversal::names init_view_pointer_member_pre_names_; - traversal::names init_view_pointer_member_post_names_; - - instance init_id_value_member_; - instance init_id_value_member_id_image_; - instance init_version_value_member_; - instance init_named_version_value_member_; - instance init_discriminator_value_member_; - instance init_named_discriminator_value_member_; - }; - - struct include: virtual context - { - typedef include base; - - virtual void - generate () - { - extra_pre (); - - os << "#include " << endl - << "#include // std::memcpy" << endl; - - if (features.polymorphic_object) - os << "#include " << endl; - - os << endl; - - if (features.polymorphic_object) - os << "#include " << endl; - - if (embedded_schema) - os << "#include " << endl; - - if (multi_dynamic) - os << "#include " << endl; - - os << endl; - - os << "#include " << endl - << "#include " << endl - << "#include " << endl - << "#include " << endl - << "#include " << endl - << "#include " << endl; - - if (features.simple_object) - os << "#include " << endl; - - if (features.polymorphic_object) - os << "#include " << endl; - - if (features.no_id_object) - os << "#include " << endl; - - if (features.view) - os << "#include " << endl; - - if (features.section) - os << "#include " << endl; - - os << "#include " << endl - << "#include " << endl; - - if (options.generate_query ()) - { - if (options.generate_prepared ()) - os << "#include " << endl; - - if (features.simple_object) - os << "#include " << endl; - - if (features.polymorphic_object) - os << "#include " << endl; - - if (features.no_id_object) - os << "#include " << endl; - - if (features.view) - os << "#include " << endl; - } - - extra_post (); - - os << endl; - } - - virtual void - extra_pre () - { - } - - virtual void - extra_post () - { - } - }; - } -} - -#endif // ODB_RELATIONAL_SOURCE_HXX -- cgit v1.1