summaryrefslogtreecommitdiff
path: root/odb/relational/source.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/relational/source.hxx')
-rw-r--r--odb/relational/source.hxx7150
1 files changed, 0 insertions, 7150 deletions
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
deleted file mode 100644
index a24ddef..0000000
--- a/odb/relational/source.hxx
+++ /dev/null
@@ -1,7150 +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 <map>
-#include <set>
-#include <list>
-#include <vector>
-#include <sstream>
-
-#include <odb/diagnostics.hxx>
-
-#include <odb/relational/context.hxx>
-#include <odb/relational/common.hxx>
-#include <odb/relational/schema.hxx>
-
-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_column> 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<semantics::class_&> (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<object_columns> 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<object_columns> 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*> ("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<iterator, iterator> 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<class_&> (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<class_&> (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<object_columns_list> l_cols; // Our id columns.
- instance<object_columns_list> 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*> ("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*> ("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<object_columns> 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<table_column> ("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> ("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<table_column> ("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> ("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<object_columns_list> 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<semantics::class_&> (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<object_columns_list> 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<object_columns_list> 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<object_columns_list> 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<object_columns_list> oid_cols (column_prefix_);
- oid_cols->traverse (m);
-
- instance<object_columns_list> 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<polymorphic_object_joins> 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<polymorphic_object_joins> 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<object_columns_list> 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<view_object_check> 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<view_object_check> 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<iterator, iterator> 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<semantics::class_&> (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 <typename T>
- struct bind_member_impl: bind_member, virtual member_base_impl<T>
- {
- typedef bind_member_impl base_impl;
-
- bind_member_impl (base const& x): base (x) {}
-
- typedef typename member_base_impl<T>::member_info member_info;
-
- using member_base_impl<T>::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<user_section*> (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<user_section*> (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<T>::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 <typename T>
- struct grow_member_impl: grow_member, virtual member_base_impl<T>
- {
- 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<T>::member_info member_info;
-
- using member_base_impl<T>::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<user_section*> (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<user_section*> (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<T>::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 <typename T>
- struct init_image_member_impl: init_image_member,
- virtual member_base_impl<T>
- {
- 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<T>::member_info member_info;
-
- using member_base_impl<T>::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<user_section*> (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<member_access> ("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<bool> ("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<bool> ("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<user_section*> (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> 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 <typename T>
- struct init_value_member_impl: init_value_member,
- virtual member_base_impl<T>
- {
- 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<T>::member_info member_info;
-
- using member_base_impl<T>::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<user_section*> (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<member_access> ("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<bool> ("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<bool> ("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<member_access> ("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<T>::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> 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<bool> // 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<bool> ("object-pointer-raw"));
- bool mp_raw (utype (mi.m).is_a<semantics::pointer> ());
-
- // 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<member_access> ("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<member_access> ("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<type&> (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<object_columns_list> id_cols;
- instance<object_columns_list> 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<semantics::class_&> (imf.scope ());
-
- data_member_path& inv_id (*id_member (*c));
-
- qname inv_table; // Other table name.
- string inv_qtable;
- instance<object_columns_list> inv_id_cols; // Other id column.
- instance<object_columns_list> 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<query_parameters> 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<object_columns> 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<query_parameters> 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<object_columns> 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<query_parameters> 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<query_parameters> 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<object_columns> 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<query_parameters> 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<bind_member> bm (
- "index_", "c", *it, ict, "index_type", "index");
- bm->traverse (m);
- }
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- os << "// key" << endl
- << "//" << endl;
- instance<bind_member> bm (
- "key_", "c", *kt, kct, "key_type", "key");
- bm->traverse (m);
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- os << "// value" << endl
- << "//" << endl;
- instance<bind_member> 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<bind_member> 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<bind_member> 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<bind_member> 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<bind_member> 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<bind_member> bm (
- "index_", "c", *it, ict, "index_type", "index");
- bm->traverse (m);
- }
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- os << "// key" << endl
- << "//" << endl;
- instance<bind_member> bm (
- "key_", "c", *kt, kct, "key_type", "key");
- bm->traverse (m);
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- os << "// value" << endl
- << "//" << endl;
- instance<bind_member> 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<grow_member> gm (
- index, "index_", *it, ict, "index_type", "index");
- gm->traverse (m);
- }
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- os << "// key" << endl
- << "//" << endl;
- instance<grow_member> gm (
- index, "key_", *kt, kct, "key_type", "key");
- gm->traverse (m);
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- break;
- }
- }
-
- os << "// value" << endl
- << "//" << endl;
- instance<grow_member> 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<init_image_member> 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<init_image_member> im (
- "key_", "*k", *kt, kct, "key_type", "key");
- im->traverse (m);
-
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- break;
- }
- }
-
- os << "// value" << endl
- << "//" << endl;
- {
- instance<init_image_member> 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<init_image_member> 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<init_value_member> im (
- "index_", "j", *it, ict, "index_type", "index");
- im->traverse (m);
- }
-
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- os << "// key" << endl
- << "//" << endl;
-
- instance<init_value_member> 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<init_value_member> 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<member_access> (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<member_access> (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<user_section*> (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> ("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<bind_member> 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<grow_member> 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<init_value_member> 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<init_image_member> 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<object_columns_list> 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<object_columns> 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<polymorphic_object_joins> 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<object_joins> 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<query_parameters> 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<query_parameters> 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<object_columns> 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<container_calls> 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<container_calls> 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<object_type&> (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;
- }
-
- 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),
- 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),
- 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<view_query> ("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<container_traits> 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> query_columns_type_;
- instance<view_query_columns_type> view_query_columns_type_;
-
- size_t index_;
- instance<grow_base> grow_base_;
- traversal::inherits grow_base_inherits_;
- instance<grow_member> grow_member_;
- traversal::names grow_member_names_;
- instance<grow_member> grow_version_member_;
- instance<grow_member> grow_discriminator_member_;
-
-
- instance<bind_base> bind_base_;
- traversal::inherits bind_base_inherits_;
- instance<bind_member> bind_member_;
- traversal::names bind_member_names_;
- instance<bind_member> bind_id_member_;
- instance<bind_member> bind_version_member_;
- instance<bind_member> bind_discriminator_member_;
-
- instance<init_image_base> init_image_base_;
- traversal::inherits init_image_base_inherits_;
- instance<init_image_member> init_image_member_;
- traversal::names init_image_member_names_;
-
- instance<init_image_member> init_id_image_member_;
- instance<init_image_member> init_version_image_member_;
-
- instance<init_value_base> init_value_base_;
- traversal::inherits init_value_base_inherits_;
- instance<init_value_member> init_value_member_;
- traversal::names init_value_member_names_;
-
- instance<init_view_pointer_member> init_view_pointer_member_pre_;
- instance<init_view_pointer_member> init_view_pointer_member_post_;
- traversal::names init_view_pointer_member_pre_names_;
- traversal::names init_view_pointer_member_post_names_;
-
- instance<init_value_member> init_id_value_member_;
- instance<init_value_member> init_id_value_member_id_image_;
- instance<init_value_member> init_version_value_member_;
- instance<init_value_member> init_named_version_value_member_;
- instance<init_value_member> init_discriminator_value_member_;
- instance<init_value_member> init_named_discriminator_value_member_;
- };
-
- struct include: virtual context
- {
- typedef include base;
-
- virtual void
- generate ()
- {
- extra_pre ();
-
- os << "#include <cassert>" << endl
- << "#include <cstring> // std::memcpy" << endl;
-
- if (features.polymorphic_object)
- os << "#include <typeinfo>" << endl;
-
- os << endl;
-
- if (features.polymorphic_object)
- os << "#include <odb/polymorphic-map.hxx>" << endl;
-
- if (embedded_schema)
- os << "#include <odb/schema-catalog-impl.hxx>" << endl;
-
- if (multi_dynamic)
- os << "#include <odb/function-table.hxx>" << endl;
-
- os << endl;
-
- os << "#include <odb/" << db << "/traits.hxx>" << endl
- << "#include <odb/" << db << "/database.hxx>" << endl
- << "#include <odb/" << db << "/transaction.hxx>" << endl
- << "#include <odb/" << db << "/connection.hxx>" << endl
- << "#include <odb/" << db << "/statement.hxx>" << endl
- << "#include <odb/" << db << "/statement-cache.hxx>" << endl;
-
- if (features.simple_object)
- os << "#include <odb/" << db << "/simple-object-statements.hxx>" << endl;
-
- if (features.polymorphic_object)
- os << "#include <odb/" << db << "/polymorphic-object-statements.hxx>" << endl;
-
- if (features.no_id_object)
- os << "#include <odb/" << db << "/no-id-object-statements.hxx>" << endl;
-
- if (features.view)
- os << "#include <odb/" << db << "/view-statements.hxx>" << endl;
-
- if (features.section)
- os << "#include <odb/" << db << "/section-statements.hxx>" << endl;
-
- os << "#include <odb/" << db << "/container-statements.hxx>" << endl
- << "#include <odb/" << db << "/exceptions.hxx>" << endl;
-
- if (options.generate_query ())
- {
- if (options.generate_prepared ())
- os << "#include <odb/" << db << "/prepared-query.hxx>" << endl;
-
- if (features.simple_object)
- os << "#include <odb/" << db << "/simple-object-result.hxx>" << endl;
-
- if (features.polymorphic_object)
- os << "#include <odb/" << db << "/polymorphic-object-result.hxx>" << endl;
-
- if (features.no_id_object)
- os << "#include <odb/" << db << "/no-id-object-result.hxx>" << endl;
-
- if (features.view)
- os << "#include <odb/" << db << "/view-result.hxx>" << endl;
- }
-
- extra_post ();
-
- os << endl;
- }
-
- virtual void
- extra_pre ()
- {
- }
-
- virtual void
- extra_post ()
- {
- }
- };
- }
-}
-
-#endif // ODB_RELATIONAL_SOURCE_HXX