summaryrefslogtreecommitdiff
path: root/odb
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-02-17 10:08:18 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-02-22 12:29:43 +0200
commit3a1eed21d4d5d0e7f6a9f400420fdc28d7be9b61 (patch)
tree97ba7338fb804c264c9eaaaa41085b08f6483c68 /odb
parent3f73cc933b64d7d9a88325d33a3c33a0e28720c6 (diff)
Add support for composite object ids
New pragma id_type (member). New test: common/composite-id. The composite example has also been updated.
Diffstat (limited to 'odb')
-rw-r--r--odb/common.cxx254
-rw-r--r--odb/common.hxx176
-rw-r--r--odb/context.cxx70
-rw-r--r--odb/context.hxx17
-rw-r--r--odb/gcc.hxx1
-rw-r--r--odb/odb.cxx20
-rw-r--r--odb/pragma.cxx13
-rw-r--r--odb/relational/common.cxx259
-rw-r--r--odb/relational/common.hxx189
-rw-r--r--odb/relational/common.txx112
-rw-r--r--odb/relational/header.hxx41
-rw-r--r--odb/relational/model.hxx328
-rw-r--r--odb/relational/mssql/common.cxx103
-rw-r--r--odb/relational/mssql/common.hxx132
-rw-r--r--odb/relational/mssql/context.cxx17
-rw-r--r--odb/relational/mssql/context.hxx8
-rw-r--r--odb/relational/mssql/model.cxx2
-rw-r--r--odb/relational/mssql/source.cxx343
-rw-r--r--odb/relational/mysql/common.cxx103
-rw-r--r--odb/relational/mysql/common.hxx118
-rw-r--r--odb/relational/mysql/context.cxx17
-rw-r--r--odb/relational/mysql/context.hxx7
-rw-r--r--odb/relational/mysql/model.cxx2
-rw-r--r--odb/relational/mysql/source.cxx361
-rw-r--r--odb/relational/oracle/common.cxx101
-rw-r--r--odb/relational/oracle/common.hxx118
-rw-r--r--odb/relational/oracle/context.cxx17
-rw-r--r--odb/relational/oracle/context.hxx8
-rw-r--r--odb/relational/oracle/model.cxx4
-rw-r--r--odb/relational/oracle/source.cxx356
-rw-r--r--odb/relational/pgsql/common.cxx101
-rw-r--r--odb/relational/pgsql/common.hxx118
-rw-r--r--odb/relational/pgsql/context.cxx17
-rw-r--r--odb/relational/pgsql/context.hxx8
-rw-r--r--odb/relational/pgsql/model.cxx2
-rw-r--r--odb/relational/pgsql/source.cxx436
-rw-r--r--odb/relational/processor.cxx147
-rw-r--r--odb/relational/source.hxx1096
-rw-r--r--odb/relational/sqlite/common.cxx103
-rw-r--r--odb/relational/sqlite/common.hxx118
-rw-r--r--odb/relational/sqlite/context.cxx17
-rw-r--r--odb/relational/sqlite/context.hxx8
-rw-r--r--odb/relational/sqlite/model.cxx2
-rw-r--r--odb/relational/sqlite/source.cxx340
-rw-r--r--odb/validator.cxx583
45 files changed, 2867 insertions, 3526 deletions
diff --git a/odb/common.cxx b/odb/common.cxx
index 230e674..6261b85 100644
--- a/odb/common.cxx
+++ b/odb/common.cxx
@@ -16,6 +16,12 @@ traverse_simple (semantics::data_member&)
}
void object_members_base::
+traverse_pointer (semantics::data_member& m, semantics::class_& c)
+{
+ traverse_member (m, utype (*id_member (c)));
+}
+
+void object_members_base::
traverse_composite (semantics::data_member*, semantics::class_& c)
{
inherits (c);
@@ -51,26 +57,6 @@ traverse_view (semantics::class_& c)
}
void object_members_base::
-traverse (semantics::data_member& m, semantics::class_& c)
-{
- // We are starting from the member. Add an empty chain which
- // corresponds to the scope that contains this member.
- //
- //member_scope_.push_back (class_inheritance_chain ());
- //member_path_.push_back (&m);
-
- member_scope_.push_back (class_inheritance_chain ());
- member_scope_.back ().push_back (&c);
-
- traverse_composite_wrapper (&m, c, 0);
-
- member_scope_.pop_back ();
-
- //member_path_.pop_back ();
- //member_scope_.pop_back ();
-}
-
-void object_members_base::
traverse (semantics::class_& c)
{
class_kind_type k (class_kind (c));
@@ -156,68 +142,73 @@ traverse (semantics::class_& c)
context::cur_object = prev;
}
-void object_members_base::member::
-traverse (semantics::data_member& m)
+void object_members_base::
+traverse_member (semantics::data_member& m, semantics::type& t)
{
- if (transient (m))
- return;
-
- om_.member_path_.push_back (&m);
-
- semantics::type& t (utype (m));
-
if (semantics::class_* comp = context::composite_wrapper (t))
{
- om_.member_scope_.push_back (class_inheritance_chain ());
- om_.member_scope_.back ().push_back (comp);
+ member_scope_.push_back (class_inheritance_chain ());
+ member_scope_.back ().push_back (comp);
qname old_table_prefix;
string old_flat_prefix, old_member_prefix;
- if (om_.build_flat_prefix_)
+ if (build_flat_prefix_)
{
- old_flat_prefix = om_.flat_prefix_;
- om_.flat_prefix_ += om_.public_name (m);
- om_.flat_prefix_ += '_';
+ old_flat_prefix = flat_prefix_;
+ flat_prefix_ += public_name (m);
+ flat_prefix_ += '_';
}
- if (om_.build_member_prefix_)
+ if (build_member_prefix_)
{
- old_member_prefix = om_.member_prefix_;
- om_.member_prefix_ += m.name ();
- om_.member_prefix_ += '.';
+ old_member_prefix = member_prefix_;
+ member_prefix_ += m.name ();
+ member_prefix_ += '.';
}
- if (om_.build_table_prefix_)
+ if (build_table_prefix_)
{
- old_table_prefix = om_.table_prefix_.prefix;
- append (m, om_.table_prefix_);
+ old_table_prefix = table_prefix_.prefix;
+ append (m, table_prefix_);
}
- om_.traverse_composite_wrapper (&m, *comp, (wrapper (t) ? &t : 0));
+ traverse_composite_wrapper (&m, *comp, (wrapper (t) ? &t : 0));
- if (om_.build_table_prefix_)
+ if (build_table_prefix_)
{
- om_.table_prefix_.level--;
- om_.table_prefix_.prefix = old_table_prefix;
+ table_prefix_.level--;
+ table_prefix_.prefix = old_table_prefix;
}
- if (om_.build_flat_prefix_)
- om_.flat_prefix_ = old_flat_prefix;
+ if (build_flat_prefix_)
+ flat_prefix_ = old_flat_prefix;
- if (om_.build_member_prefix_)
- om_.member_prefix_ = old_member_prefix;
+ if (build_member_prefix_)
+ member_prefix_ = old_member_prefix;
- om_.member_scope_.pop_back ();
+ member_scope_.pop_back ();
}
- else if (semantics::type* c = context::container (m))
- {
+ else
+ traverse_simple (m);
+}
+
+void object_members_base::member::
+traverse (semantics::data_member& m)
+{
+ if (transient (m))
+ return;
+
+ om_.member_path_.push_back (&m);
+
+ semantics::type& t (utype (m));
+
+ if (semantics::type* c = context::container (m))
om_.traverse_container (m, *c);
- }
+ else if (semantics::class_* c = object_pointer (t))
+ om_.traverse_pointer (m, *c);
else
- {
- om_.traverse_simple (m);
- }
+ om_.traverse_member (m, t);
om_.member_path_.pop_back ();
}
@@ -283,6 +274,18 @@ flush ()
{
}
+bool object_columns_base::
+traverse_column (semantics::data_member&, string const&, bool)
+{
+ return false;
+}
+
+void object_columns_base::
+traverse_pointer (semantics::data_member& m, semantics::class_& c)
+{
+ traverse_member (m, utype (*id_member (c)));
+}
+
void object_columns_base::
traverse_composite (semantics::data_member*, semantics::class_& c)
{
@@ -307,30 +310,39 @@ traverse_view (semantics::class_& c)
void object_columns_base::
traverse (semantics::data_member& m,
- semantics::class_& c,
- string const& key_prefix,
- string const& default_name)
+ semantics::type& t,
+ std::string const& kp,
+ std::string const& dn,
+ semantics::class_* to)
{
- // We are starting from the member. Add an empty chain which
- // corresponds to the scope that contains this member.
- //
- //member_scope_.push_back (class_inheritance_chain ());
- //member_path_.push_back (&m);
+ semantics::class_* oto (context::top_object);
- member_scope_.push_back (class_inheritance_chain ());
- member_scope_.back ().push_back (&c);
+ if (to != 0)
+ context::top_object = to;
- column_prefix_ = column_prefix (m, key_prefix, default_name);
+ semantics::class_* c (object_pointer (t));
+ semantics::type* rt (c == 0 ? &t : &utype (*id_member (*c)));
- traverse_composite (&m, c);
+ root_ = &m;
+ root_id_ = (kp.empty () ? context::id (m) : kp == "id");
+ root_op_ = (c != 0);
- if (!member_.first_)
- flush ();
+ key_prefix_ = kp;
+ default_name_ = dn;
- member_scope_.pop_back ();
+ if (root_op_)
+ traverse_pointer (m, *c);
+ else
+ traverse_member (m, *rt);
+
+ key_prefix_.clear ();
+ default_name_.clear ();
+
+ if (!first_ && composite_wrapper (*rt))
+ flush ();
- //member_path_.pop_back ();
- //member_scope_.pop_back ();
+ root_ = 0;
+ context::top_object = oto;
}
void object_columns_base::
@@ -386,7 +398,7 @@ traverse (semantics::class_& c)
context::cur_object = prev;
}
- if (f && !member_.first_)
+ if (f && !first_)
flush ();
}
@@ -421,48 +433,102 @@ column_prefix (semantics::data_member& m, string const& kp, string const& dn)
return r;
}
-void object_columns_base::member::
-traverse (semantics::data_member& m)
+string object_columns_base::
+column_prefix (data_member_path const& mp)
{
- if (transient (m))
- return;
+ if (mp.size () < 2)
+ return "";
- oc_.member_path_.push_back (&m);
+ string r;
- semantics::type& t (utype (m));
+ for (data_member_path::const_iterator i (mp.begin ()), e (mp.end () - 1);
+ i != e; ++i)
+ r += column_prefix (**i);
+
+ return r;
+}
+void object_columns_base::
+traverse_member (semantics::data_member& m, semantics::type& t)
+{
if (semantics::class_* comp = composite_wrapper (t))
{
- oc_.member_scope_.push_back (class_inheritance_chain ());
- oc_.member_scope_.back ().push_back (comp);
+ member_scope_.push_back (class_inheritance_chain ());
+ member_scope_.back ().push_back (comp);
- string old_prefix (oc_.column_prefix_);
- oc_.column_prefix_ += column_prefix (m);
+ string old_prefix (column_prefix_);
+ column_prefix_ += column_prefix (m, key_prefix_, default_name_);
- oc_.traverse_composite (&m, *comp);
+ // Save and clear the key prefix and default name.
+ //
+ string old_kp, old_dn;
+ old_kp.swap (key_prefix_);
+ old_dn.swap (default_name_);
- oc_.column_prefix_ = old_prefix;
+ traverse_composite (&m, *comp);
- oc_.member_scope_.pop_back ();
- }
- else if (container (m))
- {
- // Container gets its own table, so nothing to do here.
- //
+ old_kp.swap (key_prefix_);
+ old_dn.swap (default_name_);
+
+ column_prefix_ = old_prefix;
+ member_scope_.pop_back ();
}
else
{
- if (oc_.traverse_column (m, oc_.column_prefix_ + column_name (m), first_))
+ string name (column_prefix_ + column_name (m, key_prefix_, default_name_));
+
+ if (traverse_column (m, name, first_))
{
if (first_)
first_ = false;
}
}
+}
+
+void object_columns_base::member::
+traverse (semantics::data_member& m)
+{
+ if (transient (m))
+ return;
+
+ // Container gets its own table, so nothing to do here.
+ //
+ if (container (m))
+ return;
+
+ oc_.member_path_.push_back (&m);
+
+ semantics::type& t (utype (m));
+
+ if (semantics::class_* c = object_pointer (t))
+ oc_.traverse_pointer (m, *c);
+ else
+ oc_.traverse_member (m, t);
oc_.member_path_.pop_back ();
}
//
+// object_columns_list
+//
+
+void object_columns_list::
+traverse_pointer (semantics::data_member& m, semantics::class_& c)
+{
+ // Ignore inverse object pointers.
+ //
+ if (!ignore_inverse_ || !inverse (m, key_prefix_))
+ object_columns_base::traverse_pointer (m, c);
+}
+
+bool object_columns_list::
+traverse_column (semantics::data_member& m, std::string const& name, bool)
+{
+ columns_.push_back (column (name, column_type (), m));
+ return true;
+}
+
+//
// typedefs
//
diff --git a/odb/common.hxx b/odb/common.hxx
index 28ed2c1..ffbd2d6 100644
--- a/odb/common.hxx
+++ b/odb/common.hxx
@@ -6,7 +6,9 @@
#define ODB_COMMON_HXX
#include <string>
+#include <vector>
#include <cstddef> // std::size_t
+#include <cassert>
#include <odb/context.hxx>
@@ -18,6 +20,14 @@ struct object_members_base: traversal::class_, virtual context
virtual void
traverse_simple (semantics::data_member&);
+ // Traverse object pointer. The second argument is the pointed-to
+ // class. When overriding this function, you will most likely want
+ // to call the base in order to traverse the pointer as a simple
+ // member (simple object id) or as composite (composite object id).
+ //
+ virtual void
+ traverse_pointer (semantics::data_member&, semantics::class_&);
+
// If you override this function, you can call the base to traverse
// bases and members. The first argument is the data member and can
// be NULL if we are traversing the root type or a base. The second
@@ -81,11 +91,6 @@ public:
virtual void
traverse (semantics::class_&);
- // Composite value with data member.
- //
- virtual void
- traverse (semantics::data_member&, semantics::class_& comp);
-
public:
// Append composite member prefix.
//
@@ -93,13 +98,21 @@ public:
append (semantics::data_member&, table_prefix&);
protected:
- std::string flat_prefix_;
+ string flat_prefix_;
table_prefix table_prefix_;
- std::string member_prefix_;
+ string member_prefix_;
data_member_path member_path_;
data_member_scope member_scope_;
+protected:
+ semantics::data_member*
+ id () const
+ {
+ assert (!member_path_.empty ());
+ return context::id (member_path_);
+ }
+
private:
void
init (bool build_flat_prefix,
@@ -115,6 +128,9 @@ private:
}
private:
+ virtual void
+ traverse_member (semantics::data_member&, semantics::type&);
+
struct member: traversal::data_member
{
member (object_members_base& om)
@@ -148,8 +164,16 @@ struct object_columns_base: traversal::class_, virtual context
//
virtual bool
traverse_column (semantics::data_member&,
- std::string const& name,
- bool first) = 0;
+ string const& name,
+ bool first);
+
+ // Traverse object pointer. The second argument is the pointed-to
+ // class. When overriding this function, you will most likely want
+ // to call the base in order to traverse the member as a column
+ // (simple object id) or columns (composite object id).
+ //
+ virtual void
+ traverse_pointer (semantics::data_member&, semantics::class_&);
// If you override this function, you can call the base to traverse
// bases and members. The first argument is the data member and can
@@ -179,14 +203,22 @@ struct object_columns_base: traversal::class_, virtual context
flush ();
public:
- object_columns_base ()
- : top_level_ (true), member_ (*this)
+ object_columns_base (bool first = true,
+ string const& column_prefix = string ())
+ : column_prefix_ (column_prefix),
+ root_ (0),
+ first_ (first),
+ top_level_ (true),
+ member_ (*this)
{
init ();
}
- object_columns_base (object_columns_base const&)
+ object_columns_base (object_columns_base const& x)
: context (), //@@ -Wextra
+ column_prefix_ (x.column_prefix_),
+ root_ (0),
+ first_ (x.first_),
top_level_ (true),
member_ (*this)
{
@@ -196,28 +228,76 @@ public:
virtual void
traverse (semantics::class_&);
- // Composite value with data member.
+ // Traverse a data member with type, which can be a simple or composite
+ // value type, or an object pointer (with a simple or composite id).
//
virtual void
+ traverse (semantics::data_member& m)
+ {
+ traverse (m, utype (m), string (), string ());
+ }
+
+ virtual void
traverse (semantics::data_member&,
- semantics::class_& comp,
- std::string const& key_prefix,
- std::string const& default_name);
+ semantics::type&,
+ string const& key_prefix,
+ string const& default_name,
+ semantics::class_* top_object = 0); // If not 0, switch top object.
public:
// Return column prefix for composite data member.
//
static string
column_prefix (semantics::data_member&,
- std::string const& key_prefix = std::string (),
- std::string const& default_name = std::string ());
+ string const& key_prefix = string (),
+ string const& default_name = string ());
+
+ // Return column prefix up to (but not including) the last member
+ // in the path.
+ //
+ static string
+ column_prefix (data_member_path const&);
protected:
+ string key_prefix_;
+ string default_name_;
+
string column_prefix_;
data_member_path member_path_;
data_member_scope member_scope_;
+protected:
+ semantics::data_member*
+ id () const
+ {
+ if (root_ != 0)
+ return root_id_ ? root_ : 0; // Cannot have ids below root.
+ else
+ {
+ assert (!member_path_.empty ());
+ return context::id (member_path_);
+ }
+ }
+
+ string
+ column_type ()
+ {
+ if (member_path_.empty ())
+ {
+ assert (root_ != 0);
+ return context::column_type (*root_, key_prefix_);
+ }
+ else
+ return context::column_type (
+ member_path_, key_prefix_, (root_ != 0 && (root_id_ || root_op_)));
+ }
+
+private:
+ semantics::data_member* root_; // Root member if traversing from a member.
+ bool root_id_; // True if traversing root as object id.
+ bool root_op_; // True if traversing root as object pointer.
+
private:
void
init ()
@@ -227,21 +307,21 @@ private:
}
private:
+ virtual void
+ traverse_member (semantics::data_member&, semantics::type&);
+
struct member: traversal::data_member, context
{
- member (object_columns_base& oc)
- : oc_ (oc), first_ (true)
- {
- }
+ member (object_columns_base& oc): oc_ (oc) {}
virtual void
traverse (semantics::data_member&);
public:
object_columns_base& oc_;
- bool first_;
};
+ bool first_;
bool top_level_;
member member_;
@@ -249,6 +329,56 @@ private:
traversal::inherits inherits_;
};
+struct object_columns_list: object_columns_base
+{
+ object_columns_list (bool ignore_inverse = true)
+ : ignore_inverse_ (ignore_inverse)
+ {
+ }
+
+ object_columns_list (string const& column_prefix, bool ignore_inverse = true)
+ : object_columns_base (true, column_prefix),
+ ignore_inverse_ (ignore_inverse)
+ {
+ }
+
+ struct column
+ {
+ column (std::string const& n,
+ std::string const& t,
+ semantics::data_member& m)
+ : name (n), type (t), member (&m)
+ {
+ }
+
+ std::string name;
+ std::string type;
+ semantics::data_member* member;
+ };
+
+ typedef std::vector<column> columns;
+ typedef columns::const_iterator iterator;
+
+ iterator
+ begin () const {return columns_.begin ();}
+
+ iterator
+ end () const {return columns_.end ();}
+
+ columns::size_type
+ size () const {return columns_.size ();}
+
+ virtual void
+ traverse_pointer (semantics::data_member&, semantics::class_&);
+
+ virtual bool
+ traverse_column (semantics::data_member&, string const&, bool);
+
+private:
+ bool ignore_inverse_;
+ columns columns_;
+};
+
// Traverse composite values that are class template instantiations.
//
struct typedefs: traversal::typedefs, context
diff --git a/odb/context.cxx b/odb/context.cxx
index f4fa651..15579f3 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -210,6 +210,32 @@ context ()
context* context::current_;
+semantics::data_member* context::
+id (data_member_path const& mp)
+{
+ for (data_member_path::const_reverse_iterator i (mp.rbegin ());
+ i != mp.rend (); ++i)
+ {
+ if (id (**i))
+ return *i;
+ }
+
+ return 0;
+}
+
+semantics::data_member* context::
+object_pointer (data_member_path const& mp)
+{
+ for (data_member_path::const_reverse_iterator i (mp.rbegin ());
+ i != mp.rend (); ++i)
+ {
+ if (object_pointer (utype (**i)))
+ return *i;
+ }
+
+ return 0;
+}
+
bool context::
readonly (data_member_path const& mp, data_member_scope const& ms)
{
@@ -767,6 +793,9 @@ column_name (data_member_path const& mp) const
string context::
column_name (semantics::data_member& m, string const& p, string const& d) const
{
+ if (p.empty () && d.empty ())
+ return column_name (m);
+
// A container column name can be specified for the member or for the
// container type.
//
@@ -786,6 +815,23 @@ column_name (semantics::data_member& m, string const& p, string const& d) const
}
string context::
+column_type (const data_member_path& mp, string const& kp, bool id)
+{
+ if (kp.empty ())
+ {
+ // Return the id type if this member is or is a part of an object id
+ // or pointer to object.
+ //
+ return mp.back ()->get<string> (
+ id || context::id (mp) || object_pointer (mp)
+ ? "column-id-type"
+ : "column-type");
+ }
+ else
+ return indirect_value<string> (*mp.back (), kp + "-column-type");
+}
+
+string context::
column_type (semantics::data_member& m, string const& kp)
{
return kp.empty ()
@@ -1221,14 +1267,23 @@ namespace
struct column_count_impl: object_members_base
{
virtual void
+ traverse_pointer (semantics::data_member& m, semantics::class_& c)
+ {
+ size_t t (c_.total);
+
+ object_members_base::traverse_pointer (m, c);
+
+ if (context::inverse (m))
+ c_.inverse += (c_.total - t);
+ }
+
+ virtual void
traverse_simple (semantics::data_member& m)
{
c_.total++;
- if (m.count ("id"))
+ if (id ())
c_.id++;
- else if (context::inverse (m))
- c_.inverse++;
else if (context::readonly (member_path_, member_scope_))
c_.readonly++;
else if (context::version (m))
@@ -1268,6 +1323,15 @@ namespace
}
virtual void
+ traverse_pointer (semantics::data_member&, semantics::class_&)
+ {
+ if (context::is_a (member_path_, member_scope_, flags_))
+ r_++;
+
+ // No need to go inside.
+ }
+
+ virtual void
traverse_simple (semantics::data_member&)
{
if (context::is_a (member_path_, member_scope_, flags_))
diff --git a/odb/context.hxx b/odb/context.hxx
index e67af48..7e62161 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -364,6 +364,12 @@ public:
return t.get<semantics::class_*> ("element-type", 0);
}
+ // If this data member is or is part of an object pointer, then
+ // return the member that is the pointer. Otherwise, return 0.
+ //
+ static semantics::data_member*
+ object_pointer (data_member_path const&);
+
static bool
abstract (semantics::class_& c)
{
@@ -385,6 +391,12 @@ public:
return m.count ("id");
}
+ // If this data member is or is part of an id member, then return
+ // the member that is marked as the id. Otherwise, return 0.
+ //
+ static semantics::data_member*
+ id (data_member_path const&);
+
static bool
auto_ (semantics::data_member& m)
{
@@ -500,6 +512,11 @@ public:
string const& default_name) const;
string
+ column_type (const data_member_path&,
+ string const& key_prefix = string (),
+ bool id = false); // Pass true if this type is object id other
+ // than because of the members in the path.
+ string
column_type (semantics::data_member&, string const& key_prefix = string ());
string
diff --git a/odb/gcc.hxx b/odb/gcc.hxx
index a9da1bd..da77027 100644
--- a/odb/gcc.hxx
+++ b/odb/gcc.hxx
@@ -42,6 +42,7 @@ extern "C"
#endif
#include <diagnostic.h>
+#include <output.h>
}
#ifndef LOCATION_COLUMN
diff --git a/odb/odb.cxx b/odb/odb.cxx
index dd9b180..b17369a 100644
--- a/odb/odb.cxx
+++ b/odb/odb.cxx
@@ -692,6 +692,26 @@ main (int argc, char* argv[])
<< "#endif" << endl
<< endl;
+ // Add ODB compiler metaprogramming tests.
+ //
+ os << "namespace odb" << endl
+ << "{" << endl
+ << "namespace compiler" << endl
+ << "{" << endl;
+
+ // operator< test, used in validator.
+ //
+ os << "template <typename T>" << endl
+ << "bool" << endl
+ << "has_lt_operator (T const& x, T const& y)" << endl
+ << "{" << endl
+ << "bool r (x < y);" << endl
+ << "return r;" << endl
+ << "}" << endl;
+
+ os << "}" << endl
+ << "}" << endl;
+
// Add custom prologue if any.
//
// NOTE: if you change the format, you also need to update code
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index 5149bee..6c92f0f 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -493,18 +493,8 @@ check_spec_decl_type (tree d,
return false;
}
}
- else if (p == "id_type")
- {
- // Id type can only be used for types.
- //
- if (!TYPE_P (d))
- {
- error (l) << "name '" << name << "' in db pragma " << p << " does "
- << "not refer to a type" << endl;
- return false;
- }
- }
else if (p == "type" ||
+ p == "id_type" ||
p == "value_type" ||
p == "index_type" ||
p == "key_type")
@@ -1841,6 +1831,7 @@ handle_pragma_qualifier (cpp_reader* reader, string const& p)
p == "key_options" ||
p == "id_options" ||
p == "type" ||
+ p == "id_type" ||
p == "value_type" ||
p == "index_type" ||
p == "key_type" ||
diff --git a/odb/relational/common.cxx b/odb/relational/common.cxx
index bf325f7..381d77f 100644
--- a/odb/relational/common.cxx
+++ b/odb/relational/common.cxx
@@ -78,16 +78,11 @@ namespace relational
}
}
- bool query_columns_base::
- traverse_column (semantics::data_member& m, string const& column, bool)
+ void query_columns_base::
+ traverse_pointer (semantics::data_member& m, semantics::class_& c)
{
- semantics::class_* ptr (object_pointer (utype (m)));
-
- if (ptr == 0)
- return false;
-
string name (public_name (m));
- bool inv (inverse (m));
+ bool inv (inverse (m, key_prefix_));
if (decl_)
{
@@ -101,7 +96,7 @@ namespace relational
os << "typedef" << endl
<< "odb::query_pointer<" << endl
<< " odb::pointer_query_columns<" << endl
- << " " << class_fq_name (*ptr) << "," << endl
+ << " " << class_fq_name (c) << "," << endl
<< " " << name << "_alias_ > >" << endl
<< name << "_type_ ;"
<< endl
@@ -111,11 +106,32 @@ namespace relational
}
else
{
- // For now use column name as table alias.
- // @@ This will become problematic when we add support for composite ids.
+ // Come up with a table alias. Generally, we want it 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;
+
+ if (composite_wrapper (utype ((*id_member (c)))))
+ {
+ string p (column_prefix (m, key_prefix_, default_name_));
+
+ if (p.empty ())
+ p = public_name_db (m);
+ else
+ p.resize (p.size () - 1); // Remove trailing underscore.
+
+ alias = column_prefix_ + p;
+ }
+ else
+ alias = column_prefix_ + column_name (m, key_prefix_, default_name_);
+
os << "const char " << scope_ << "::" << name << "_alias_[] = " <<
- strlit (quote_id (column)) << ";"
+ strlit (quote_id (alias)) << ";"
<< endl;
if (inv)
@@ -123,8 +139,6 @@ namespace relational
<< scope_ << "::" << name << ";"
<< endl;
}
-
- return true;
}
// query_columns
@@ -132,13 +146,13 @@ namespace relational
query_columns::
query_columns (bool ptr)
- : ptr_ (ptr), decl_ (true)
+ : ptr_ (ptr), decl_ (true), in_ptr_ (false)
{
}
query_columns::
query_columns (bool ptr, semantics::class_& c) //@@ context::{cur,top}_object
- : ptr_ (ptr), decl_ (false)
+ : ptr_ (ptr), decl_ (false), in_ptr_ (false)
{
scope_ = ptr ? "pointer_query_columns" : "query_columns";
scope_ += "< " + class_fq_name (c) + ", table >";
@@ -164,12 +178,13 @@ namespace relational
}
string name (public_name (*m));
+ string suffix (in_ptr_ ? "_column_type_" : "_type_");
if (decl_)
{
os << "// " << name << endl
<< "//" << endl
- << "struct " << name << "_type_";
+ << "struct " << name << suffix;
// Derive from the base in query_columns_base. It contains columns
// data for the pointer members.
@@ -178,27 +193,29 @@ namespace relational
os << ": " << name << "_base_";
os << "{"
- << name << "_type_ (){}"; // For some reason GCC needs this c-tor
- // if we make the static member const.
+ << name << suffix << " (){}"; // For some reason GCC needs this c-tor
+ // if we make the static member const.
object_columns_base::traverse_composite (m, c);
- os << "};"
- << "static const " << name << "_type_ " << name << ";"
- << endl;
+ os << "};";
+
+ if (!in_ptr_)
+ os << "static const " << name << "_type_ " << name << ";"
+ << endl;
}
else
{
// Handle nested members first.
//
string old_scope (scope_);
- scope_ += "::" + name + "_type_";
+ scope_ += "::" + name + suffix;
object_columns_base::traverse_composite (m, c);
scope_ = old_scope;
- // Composite member.
+ // Composite member. Note that here we don't use suffix.
//
os << "template <const char* table>" << endl
<< "const typename " << scope_ << "::" << name << "_type_" << endl
@@ -216,39 +233,16 @@ namespace relational
<< "}";
}
- bool query_columns::
- traverse_column (semantics::data_member& m, string const& column, bool)
+ void query_columns::
+ column_common (semantics::data_member& m,
+ string const& type,
+ string const& column,
+ string const& suffix)
{
- semantics::names* hint;
- semantics::type& t (utype (m, hint));
- semantics::class_* ptr (object_pointer (t));
-
- if (ptr != 0)
- {
- // If this is for the pointer_query_columns and the member is not
- // inverse, then create the normal member corresponding to the id
- // column. This will allow the user to check it for NULL or to
- // compare ids. In case this is for query_columns, then for the
- // inverse member everything has been generated in query_columns_base.
- //
- if (inverse (m))
- return false;
- }
-
string name (public_name (m));
if (decl_)
{
- string type;
- if (ptr != 0)
- {
- semantics::data_member& id (*id_member (*ptr));
- semantics::type& t (utype (id, hint));
- type = t.fq_name (hint);
- }
- else
- type = t.fq_name (hint);
-
string type_id (database_type_id (m));
os << "// " << name << endl
@@ -259,43 +253,14 @@ namespace relational
<< " " << db << "::value_traits<" << endl
<< " " << type << "," << endl
<< " " << type_id << " >::query_type," << endl
- << " " << type_id << " >" << endl;
-
- if (ptr == 0 || ptr_)
- os << name << "_type_;"
- << endl;
- else
- {
- os << name << "_column_type_;"
- << endl
- << "typedef" << endl
- << "odb::query_pointer<" << endl
- << " odb::pointer_query_columns<" << endl
- << " " << class_fq_name (*ptr) << "," << endl
- << " " << name << "_alias_ > >" << endl
- << name << "_pointer_type_;"
- << endl;
-
- // If this is a non-inverse relationship, then make the column have
- // a dual interface: that of an object pointer and of an id column.
- // The latter allows the user to, for example, use the is_null()
- // test in a natural way. For inverse relationships there is no
- // column and so the column interface is not available.
- //
- os << "struct " << name << "_type_: " <<
- name << "_pointer_type_, " << name << "_column_type_"
- << "{";
-
- column_ctor (name + "_type_", name + "_column_type_");
-
- os << "};";
- }
-
- os << "static const " << name << "_type_ " << name << ";"
+ << " " << type_id << " >" << endl
+ << name << suffix << ";"
<< endl;
}
else
{
+ // Note that here we don't use suffix.
+ //
os << "template <const char* table>" << endl
<< "const typename " << scope_ << "::" << name << "_type_" << endl
<< scope_ << "::" << name << " (" << "table, " <<
@@ -306,10 +271,134 @@ namespace relational
os << ");"
<< endl;
}
+ }
+
+ bool query_columns::
+ traverse_column (semantics::data_member& m, string const& column, bool)
+ {
+ semantics::names* hint;
+ semantics::type& t (utype (m, hint));
+
+ column_common (m, t.fq_name (hint), column);
+
+ if (decl_)
+ {
+ string name (public_name (m));
+
+ os << "static const " << name << "_type_ " << name << ";"
+ << endl;
+ }
return true;
}
+ void query_columns::
+ traverse_pointer (semantics::data_member& m, semantics::class_& c)
+ {
+ // If this is for the pointer_query_columns and the member is not
+ // inverse, then create the normal member corresponding to the id
+ // column. This will allow the user to check it for NULL or to
+ // compare ids. In case this is for query_columns, then for the
+ // inverse member everything has been generated in query_columns_base.
+ //
+ if (inverse (m, key_prefix_))
+ return;
+
+ string name (public_name (m));
+
+ semantics::data_member& id (*id_member (c));
+ semantics::names* hint;
+ semantics::type& t (utype (id, hint));
+
+ if (composite_wrapper (t))
+ {
+ // Composite id.
+ //
+
+ // For pointer_query_columns generate normal composite mapping.
+ //
+ if (ptr_)
+ object_columns_base::traverse_pointer (m, c);
+ else
+ {
+ // If this is a non-inverse relationship, then make the column have
+ // a dual interface: that of an object pointer and of an id column.
+ // The latter allows the user to, for example, use the is_null()
+ // test in a natural way. For inverse relationships there is no
+ // column and so the column interface is not available.
+ //
+ in_ptr_ = true;
+ object_columns_base::traverse_pointer (m, c);
+ in_ptr_ = false;
+
+ if (decl_)
+ {
+ os << "typedef" << endl
+ << "odb::query_pointer<" << endl
+ << " odb::pointer_query_columns<" << endl
+ << " " << class_fq_name (c) << "," << endl
+ << " " << name << "_alias_ > >" << endl
+ << name << "_pointer_type_;"
+ << endl;
+
+ os << "struct " << name << "_type_: " <<
+ name << "_pointer_type_, " << name << "_column_type_"
+ << "{"
+ << "};";
+
+ os << "static const " << name << "_type_ " << name << ";"
+ << endl;
+ }
+ }
+ }
+ else
+ {
+ // Simple id.
+ //
+ string type (t.fq_name (hint));
+ string column (column_prefix_ +
+ column_name (m, key_prefix_, default_name_));
+
+ // For pointer_query_columns generate normal column mapping.
+ //
+ if (ptr_)
+ column_common (m, type, column);
+ else
+ {
+ // If this is a non-inverse relationship, then make the column have
+ // a dual interface: that of an object pointer and of an id column.
+ // The latter allows the user to, for example, use the is_null()
+ // test in a natural way. For inverse relationships there is no
+ // column and so the column interface is not available.
+ //
+ column_common (m, type, column, "_column_type_");
+
+ if (decl_)
+ {
+ os << "typedef" << endl
+ << "odb::query_pointer<" << endl
+ << " odb::pointer_query_columns<" << endl
+ << " " << class_fq_name (c) << "," << endl
+ << " " << name << "_alias_ > >" << endl
+ << name << "_pointer_type_;"
+ << endl;
+
+ os << "struct " << name << "_type_: " <<
+ name << "_pointer_type_, " << name << "_column_type_"
+ << "{";
+
+ column_ctor (name + "_type_", name + "_column_type_");
+
+ os << "};";
+ }
+ }
+
+ if (decl_)
+ os << "static const " << name << "_type_ " << name << ";"
+ << endl;
+ }
+ }
+
//
// Dynamic traversal support.
//
diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx
index d552a72..276868c 100644
--- a/odb/relational/common.hxx
+++ b/odb/relational/common.hxx
@@ -42,7 +42,7 @@ namespace relational
protected:
// For virtual inheritance only. Should not be actually called.
//
- member_base (); // {assert (false);}
+ member_base ();
protected:
string var_override_;
@@ -51,6 +51,176 @@ namespace relational
string key_prefix_;
};
+ // Template argument is the database SQL type (sql_type).
+ //
+ template <typename T>
+ struct member_base_impl: virtual member_base
+ {
+ typedef member_base_impl base_impl;
+
+ member_base_impl (base const& x): base (x) {}
+
+ protected:
+ member_base_impl () {}
+
+ public:
+ virtual T const&
+ member_sql_type (semantics::data_member&) = 0;
+
+ virtual void
+ traverse (semantics::data_member&);
+
+ struct member_info
+ {
+ semantics::data_member& m; // Member.
+ semantics::type& t; // Cvr-unqualified member C++ type, note
+ // that m.type () may not be the same as t.
+ semantics::class_* ptr; // Pointed-to object if m is an object
+ // pointer. In this case t is the id type
+ // while fq_type_ is the pointer fq-type.
+ semantics::type* wrapper; // Wrapper type if member is a composite or
+ // container wrapper, also cvr-unqualified.
+ // In this case t is the wrapped type.
+ bool cq; // True if the original (wrapper) type
+ // is const-qualified.
+ T const* st; // Member SQL type (only simple values).
+ string& var; // Member variable name with trailing '_'.
+
+ // C++ type fq-name.
+ //
+ string
+ fq_type (bool unwrap = true) const
+ {
+ semantics::names* hint;
+
+ if (wrapper != 0 && unwrap)
+ {
+ // Use the hint from the wrapper unless the wrapped type
+ // is qualified.
+ //
+ hint = wrapper->get<semantics::names*> ("wrapper-hint");
+ utype (*context::wrapper (*wrapper), hint);
+ return t.fq_name (hint);
+ }
+
+ // Use the original type from 'm' instead of 't' since the hint may
+ // be invalid for a different type. Plus, if a type is overriden,
+ // then the fq_type must be as well.
+ //
+ if (ptr != 0)
+ {
+ semantics::type& t (utype (*id_member (*ptr), hint));
+ return t.fq_name (hint);
+ }
+ else if (fq_type_.empty ())
+ {
+ semantics::type& t (utype (m, hint));
+ return t.fq_name (hint);
+ }
+ else
+ return fq_type_;
+ }
+
+ string
+ ptr_fq_type () const
+ {
+ assert (ptr != 0);
+
+ if (fq_type_.empty ())
+ {
+ // If type is overridden so should fq_type so it is safe to
+ // get the type from the member.
+ //
+ semantics::names* hint;
+ semantics::type& t (utype (m, hint));
+ return t.fq_name (hint);
+ }
+ else
+ return fq_type_;
+ }
+
+ string const& fq_type_;
+
+ member_info (semantics::data_member& m_,
+ semantics::type& t_,
+ semantics::type* wrapper_,
+ bool cq_,
+ string& var_,
+ string const& fq_type)
+ : m (m_),
+ t (t_),
+ ptr (0),
+ wrapper (wrapper_),
+ cq (cq_),
+ st (0),
+ var (var_),
+ fq_type_ (fq_type)
+ {
+ }
+ };
+
+ bool
+ container (member_info& mi)
+ {
+ // This cannot be a container if we have a type override.
+ //
+ return type_override_ == 0 && context::container (mi.m);
+ }
+
+ // The false return value indicates that no further callbacks
+ // should be called for this member.
+ //
+ virtual bool
+ pre (member_info&)
+ {
+ return true;
+ }
+
+ virtual void
+ post (member_info&)
+ {
+ }
+
+ virtual void
+ traverse_composite (member_info&)
+ {
+ }
+
+ virtual void
+ traverse_container (member_info&)
+ {
+ }
+
+ // Note that by default traverse_object_pointer() will traverse the
+ // pointed-to object id type.
+ //
+ virtual void
+ traverse_object_pointer (member_info&);
+
+ virtual void
+ traverse_simple (member_info&) = 0;
+ };
+
+ //
+ //
+ struct member_database_type_id: virtual member_base
+ {
+ typedef member_database_type_id base;
+
+ member_database_type_id (semantics::type* type = 0,
+ string const& fq_type = string (),
+ string const& key_prefix = string ())
+ : member_base (type, fq_type, key_prefix)
+ {
+ }
+
+ virtual string
+ database_type_id (semantics::data_member&)
+ {
+ assert (false);
+ }
+ };
+
//
//
struct query_columns_base: object_columns_base, virtual context
@@ -66,8 +236,8 @@ namespace relational
virtual void
traverse_composite (semantics::data_member*, semantics::class_&);
- virtual bool
- traverse_column (semantics::data_member&, string const&, bool);
+ virtual void
+ traverse_pointer (semantics::data_member&, semantics::class_&);
protected:
bool decl_;
@@ -103,13 +273,24 @@ namespace relational
virtual void
traverse_composite (semantics::data_member*, semantics::class_&);
+ virtual void
+ column_common (semantics::data_member&,
+ string const& type,
+ string const& column,
+ string const& suffix = "_type_");
+
virtual bool
traverse_column (semantics::data_member&, string const&, bool);
+ virtual void
+ traverse_pointer (semantics::data_member&, semantics::class_&);
+
protected:
bool ptr_;
bool decl_;
+ bool in_ptr_; // True if we are "inside" an object pointer.
+
string scope_;
string table_;
string default_table_;
@@ -349,4 +530,6 @@ namespace relational
}
}
+#include <odb/relational/common.txx>
+
#endif // ODB_RELATIONAL_COMMON_HXX
diff --git a/odb/relational/common.txx b/odb/relational/common.txx
new file mode 100644
index 0000000..1d3ecbf
--- /dev/null
+++ b/odb/relational/common.txx
@@ -0,0 +1,112 @@
+// file : odb/relational/common.txx
+// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+namespace relational
+{
+ //
+ // member_base_impl
+ //
+
+ template <typename T>
+ void member_base_impl<T>::
+ traverse (semantics::data_member& m)
+ {
+ if (transient (m))
+ return;
+
+ string var;
+
+ if (!var_override_.empty ())
+ var = var_override_;
+ else
+ {
+ string const& name (m.name ());
+ var = name + (name[name.size () - 1] == '_' ? "" : "_");
+ }
+
+ bool cq (type_override_ != 0 ? false : const_type (m.type ()));
+ semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m));
+
+ semantics::type* cont;
+ if (semantics::class_* c = object_pointer (t))
+ {
+ semantics::type& t (utype (*id_member (*c)));
+ semantics::class_* comp (composite_wrapper (t));
+
+ member_info mi (m,
+ (comp != 0 ? *comp : t),
+ (comp != 0 && wrapper (t) ? &t : 0),
+ cq,
+ var,
+ fq_type_override_); // Pointer type.
+
+ mi.ptr = c;
+
+ if (comp == 0)
+ mi.st = &member_sql_type (m);
+
+ if (pre (mi))
+ {
+ traverse_object_pointer (mi);
+ post (mi);
+ }
+ }
+ else if (semantics::class_* c = composite_wrapper (t))
+ {
+ // If t is a wrapper, pass the wrapped type. Also pass the
+ // original, wrapper type.
+ //
+ member_info mi (m,
+ *c,
+ (wrapper (t) ? &t : 0),
+ cq,
+ var,
+ fq_type_override_);
+ if (pre (mi))
+ {
+ traverse_composite (mi);
+ post (mi);
+ }
+ }
+ // This cannot be a container if we have a type override.
+ //
+ else if (type_override_ == 0 && (cont = context::container (m)))
+ {
+ // The same unwrapping logic as for composite values.
+ //
+ member_info mi (m,
+ *cont,
+ (wrapper (t) ? &t : 0),
+ cq,
+ var,
+ fq_type_override_);
+ if (pre (mi))
+ {
+ traverse_container (mi);
+ post (mi);
+ }
+ }
+ else
+ {
+ member_info mi (m, t, 0, cq, var, fq_type_override_);
+ mi.st = &member_sql_type (m);
+
+ if (pre (mi))
+ {
+ traverse_simple (mi);
+ post (mi);
+ }
+ }
+ }
+
+ template <typename T>
+ void member_base_impl<T>::
+ traverse_object_pointer (member_info& mi)
+ {
+ if (composite (mi.t)) // Already unwrapped.
+ traverse_composite (mi);
+ else
+ traverse_simple (mi);
+ }
+}
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index cf103b5..dda9e2a 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -441,8 +441,11 @@ namespace relational
//
size_t n;
- if (class_* kc = composite_wrapper (*kt))
- n = column_count (*kc).total;
+ class_* ptr (object_pointer (*kt));
+ semantics::type& t (ptr == 0 ? *kt : utype (*id_member (*ptr)));
+
+ if (class_* comp = composite_wrapper (t))
+ n = column_count (*comp).total;
else
n = 1;
@@ -461,19 +464,27 @@ namespace relational
//
// Value is also a key.
//
- //if (class_* vc = composite_wrapper (vt))
- // cond_columns += column_count (*vc).total;
- //else
- // cond_columns++;
-
+ // class_* ptr (object_pointer (vt));
+ // semantics::type& t (ptr == 0 ? vt : utype (*id_member (*ptr)));
+ //
+ // if (class_* comp = composite_wrapper (t))
+ // cond_columns += column_count (*comp).total;
+ // else
+ // cond_columns++;
+ //
break;
}
}
- if (class_* vc = composite_wrapper (vt))
- data_columns += column_count (*vc).total;
- else
- data_columns++;
+ {
+ class_* ptr (object_pointer (vt));
+ semantics::type& t (ptr == 0 ? vt : utype (*id_member (*ptr)));
+
+ if (class_* comp = composite_wrapper (t))
+ data_columns += column_count (*comp).total;
+ else
+ data_columns++;
+ }
// Store column counts for the source generator.
//
@@ -786,7 +797,7 @@ namespace relational
}
}
- os << "const data_image_type&, database&);"
+ os << "const data_image_type&, database*);"
<< endl;
// insert_one
@@ -1138,7 +1149,7 @@ namespace relational
// init (object, image)
//
os << "static void" << endl
- << "init (object_type&, const image_type&, database&);"
+ << "init (object_type&, const image_type&, database*);"
<< endl;
// init (id_image, id)
@@ -1503,7 +1514,7 @@ namespace relational
// init (view, image)
//
os << "static void" << endl
- << "init (view_type&, const image_type&, database&);"
+ << "init (view_type&, const image_type&, database*);"
<< endl;
// column_count
@@ -1605,7 +1616,7 @@ namespace relational
// init (value, image)
//
os << "static void" << endl
- << "init (value_type&, const image_type&, database&);"
+ << "init (value_type&, const image_type&, database*);"
<< endl;
os << "};";
diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx
index 5f6470d..66db3d6 100644
--- a/odb/relational/model.hxx
+++ b/odb/relational/model.hxx
@@ -26,12 +26,10 @@ namespace relational
{
typedef object_columns base;
- object_columns (sema_rel::model& model,
- sema_rel::table& table,
- string const& prefix = string ())
+ object_columns (sema_rel::model& model, sema_rel::table& table)
: model_ (model),
table_ (table),
- prefix_ (prefix),
+ pkey_ (0),
id_override_ (false)
{
}
@@ -77,20 +75,25 @@ namespace relational
virtual void
traverse (semantics::data_member& m,
- semantics::class_& c,
- std::string const& kp,
- std::string const& dn)
+ semantics::type& t,
+ string const& kp,
+ string const& dn,
+ semantics::class_* to = 0)
{
// This overrides the member name for a composite container value
// or key.
//
if (!kp.empty ())
{
- id_prefix_ = kp + ".";
- id_override_ = true;
+ semantics::class_* c (object_pointer (t));
+ if (composite_wrapper (c == 0 ? t : utype (*id_member (*c))))
+ {
+ id_prefix_ = kp + ".";
+ id_override_ = true;
+ }
}
- object_columns_base::traverse (m, c, kp, dn);
+ object_columns_base::traverse (m, t, kp, dn, to);
}
using object_columns_base::traverse;
@@ -98,23 +101,22 @@ namespace relational
virtual bool
traverse_column (semantics::data_member& m, string const& name, bool)
{
- // Ignore inverse object pointers.
- //
- if (inverse (m))
- return false;
+ bool id (object_columns_base::id ()); // Id or part of.
+ bool null (!id && context::null (m, key_prefix_));
- string id (id_prefix_ + (prefix_.empty () ? m.name () : prefix_));
+ string col_id (id_prefix_ +
+ (key_prefix_.empty () ? m.name () : key_prefix_));
sema_rel::column& c (
- model_.new_node<sema_rel::column> (
- id, column_type (m, prefix_), context::null (m, prefix_)));
+ model_.new_node<sema_rel::column> (col_id, column_type (), null));
+
c.set ("cxx-node", static_cast<semantics::node*> (&m));
model_.new_edge<sema_rel::unames> (table_, c, name);
// An id member cannot have a default value.
//
- if (!context::id (m))
+ if (!id)
{
string const& d (default_ (m));
@@ -124,14 +126,12 @@ namespace relational
// If we have options, add them.
//
- string const& o (column_options (m, prefix_));
+ string const& o (column_options (m, key_prefix_));
if (!o.empty ())
c.options (o);
- constraints (m, name, id, c);
- reference (m, name, id, c);
-
+ constraints (m, name, col_id, c);
return true;
}
@@ -188,58 +188,129 @@ namespace relational
string const& /* id */,
sema_rel::column& c)
{
- if (!id (m))
- return;
-
- sema_rel::primary_key& pk (
- model_.new_node<sema_rel::primary_key> (m.count ("auto")));
- pk.set ("cxx-node", static_cast<semantics::node*> (&m));
-
- model_.new_edge<sema_rel::contains> (pk, c);
-
- // In most databases the primary key constraint can be manipulated
- // without an explicit name. So we use the special empty name for
- // primary keys in order not to clash with columns and other
- // constraints. If the target database does not support unnamed
- // primary key manipulation, then the database-specific code will
- // have to come up with a suitable name.
- //
- model_.new_edge<sema_rel::unames> (table_, pk, "");
+ if (table_.is_a<sema_rel::object_table> ())
+ {
+ if (semantics::data_member* idm = id ())
+ {
+ if (pkey_ == 0)
+ {
+ pkey_ = &model_.new_node<sema_rel::primary_key> (
+ m.count ("auto"));
+ pkey_->set ("cxx-node", static_cast<semantics::node*> (idm));
+
+ // In most databases the primary key constraint can be
+ // manipulated without an explicit name. So we use the special
+ // empty name for primary keys in order not to clash with
+ // columns and other constraints. If the target database does
+ // not support unnamed primary key manipulation, then the
+ // database-specific code will have to come up with a suitable
+ // name.
+ //
+ model_.new_edge<sema_rel::unames> (table_, *pkey_, "");
+ }
+
+ model_.new_edge<sema_rel::contains> (*pkey_, c);
+ }
+ }
}
virtual void
- reference (semantics::data_member& m,
- string const& name,
- string const& id,
- sema_rel::column& c)
+ traverse_pointer (semantics::data_member& m, semantics::class_& c)
{
- semantics::class_* p (object_pointer (member_utype (m, prefix_)));
+ using sema_rel::column;
- if (p == 0)
+ // Ignore inverse object pointers.
+ //
+ if (inverse (m, key_prefix_))
return;
+ string id (id_prefix_ +
+ (key_prefix_.empty () ? m.name () : key_prefix_));
+
sema_rel::foreign_key& fk (
model_.new_node<sema_rel::foreign_key> (
id,
- table_name (*p),
+ table_name (c),
true)); // deferred
fk.set ("cxx-node", static_cast<semantics::node*> (&m));
- fk.referenced_columns ().push_back (column_name (*id_member (*p)));
+ bool simple;
+
+ // Get referenced columns.
+ //
+ {
+ semantics::data_member& idm (*id_member (c));
+
+ instance<object_columns_list> ocl;
+ ocl->traverse (idm);
+
+ for (object_columns_list::iterator i (ocl->begin ());
+ i != ocl->end (); ++i)
+ fk.referenced_columns ().push_back (i->name);
+
+ simple = (fk.referenced_columns ().size () == 1);
+ }
+
+ // Get the position of the last column.
+ //
+ sema_rel::table::names_iterator i (table_.names_end ());
+
+ while (i != table_.names_begin ())
+ {
+ --i;
+
+ if (i->nameable ().is_a<column> ())
+ break;
+ }
+
+ // Traverse the object pointer as columns.
+ //
+ object_columns_base::traverse_pointer (m, c);
- model_.new_edge<sema_rel::contains> (fk, c);
+ // Add the newly added columns to the foreign key.
+ //
+ if (i != table_.names_end ())
+ ++i;
+ else
+ i = table_.names_begin ();
+
+ for (; i != table_.names_end (); ++i)
+ {
+ if (column* c = dynamic_cast<column*> (&i->nameable ()))
+ model_.new_edge<sema_rel::contains> (fk, *c);
+ else
+ break;
+ }
// Derive the constraint name. Generally, we want it to be based
- // on the column name. This is straightforward for single column
- // references. In case of the composite ids, we will need to use
- // the column prefix which is based on the data member name,
- // unless overridden (see how the column pragma works for members
- // of composite value types). @@ This is a TODO. Perhaps use the
- // up-to-and-including composite member prefix? Though it can be
- // empty.
+ // 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.
//
- model_.new_edge<sema_rel::unames> (table_, fk, name + "_fk");
+ string name;
+
+ if (simple)
+ name = fk.contains_begin ()->column ().name ();
+ else
+ {
+ string p (column_prefix (m, key_prefix_, default_name_));
+
+ if (p.empty ())
+ p = public_name_db (m);
+
+ name = column_prefix_ + p;
+ }
+
+ // Add an underscore unless we already have one.
+ //
+ if (name[name.size () - 1] != '_')
+ name += '_';
+
+ model_.new_edge<sema_rel::unames> (table_, fk, name + "fk");
}
protected:
@@ -249,7 +320,7 @@ namespace relational
protected:
sema_rel::model& model_;
sema_rel::table& table_;
- string prefix_;
+ sema_rel::primary_key* pkey_;
string id_prefix_;
bool id_override_;
};
@@ -310,13 +381,15 @@ namespace relational
using semantics::type;
using semantics::data_member;
+ using sema_rel::index;
+ using sema_rel::column;
+
// Ignore inverse containers of object pointers.
//
if (inverse (m, "value"))
return;
container_kind_type ck (container_kind (ct));
- type& vt (container_vt (ct));
qname const& name (table_name (m, table_prefix_));
@@ -332,15 +405,14 @@ namespace relational
model_.new_edge<sema_rel::qnames> (model_, t, name);
- // object_id (simple value, for now)
+ // object_id
//
- string id_name (column_name (m, "id", "object_id"));
{
- instance<object_columns> oc (model_, t, "id");
- oc->traverse_column (m, id_name, true);
+ instance<object_columns> oc (model_, t);
+ oc->traverse (m, container_idt (m), "id", "object_id");
}
- // Foreign key for the object id.
+ // Foreign key and index for the object id.
//
{
sema_rel::foreign_key& fk (
@@ -349,105 +421,91 @@ namespace relational
table_name (*context::top_object),
false, // immediate
sema_rel::foreign_key::cascade));
-
fk.set ("cxx-node", static_cast<semantics::node*> (&m));
- fk.referenced_columns ().push_back (
- column_name (
- *id_member (*context::top_object)));
+ index& in (model_.new_node<index> (id + ".id"));
+ in.set ("cxx-node", static_cast<semantics::node*> (&m));
+
+ // Get referenced columns.
+ //
+ {
+ data_member& idm (*id_member (*context::top_object));
+
+ instance<object_columns_list> ocl;
+ ocl->traverse (idm);
+
+ for (object_columns_list::iterator i (ocl->begin ());
+ i != ocl->end (); ++i)
+ fk.referenced_columns ().push_back (i->name);
+ }
// All the columns we have in this table so far are for the
- // object id.
+ // object id. Add them to the foreign key and the index.
//
for (sema_rel::table::names_iterator i (t.names_begin ());
i != t.names_end ();
++i)
- model_.new_edge<sema_rel::contains> (
- fk, dynamic_cast<sema_rel::column&> (i->nameable ()));
+ {
+ column& c (dynamic_cast<column&> (i->nameable ()));
- // Derive the constraint name. See the comment for the other
- // foreign key code above.
+ model_.new_edge<sema_rel::contains> (fk, c);
+ model_.new_edge<sema_rel::contains> (in, c);
+ }
+
+ // Derive the names. See the comment for the other foreign key
+ // code above.
//
- model_.new_edge<sema_rel::unames> (t, fk, id_name + "_fk");
- }
+ // Note also that id_name can be a column prefix (if id is
+ // composite), in which case it can be empty and if not, then
+ // it will most likely already contain a trailing underscore.
+ //
+ string id_name (column_name (m, "id", "object_id"));
- // index (simple value)
- //
- string index_name;
- bool ordered (ck == ck_ordered && !unordered (m));
- if (ordered)
- {
- instance<object_columns> oc (model_, t, "index");
- index_name = column_name (m, "index", "index");
- oc->traverse_column (m, index_name, true);
- }
+ if (id_name.empty ())
+ id_name = "object_id";
- // key (simple or composite value)
- //
- if (ck == ck_map || ck == ck_multimap)
- {
- type& kt (container_kt (ct));
+ if (id_name[id_name.size () - 1] != '_')
+ id_name += '_';
- if (semantics::class_* ckt = composite_wrapper (kt))
- {
- instance<object_columns> oc (model_, t);
- oc->traverse (m, *ckt, "key", "key");
- }
- else
- {
- instance<object_columns> oc (model_, t, "key");
- string const& name (column_name (m, "key", "key"));
- oc->traverse_column (m, name, true);
- }
+ model_.new_edge<sema_rel::unames> (t, fk, id_name + "fk");
+
+ model_.new_edge<sema_rel::qnames> (
+ model_, in, name + "_" + id_name + "i");
}
- // value (simple or composite value)
+ // index (simple value)
//
+ bool ordered (ck == ck_ordered && !unordered (m));
+ if (ordered)
{
- if (semantics::class_* cvt = composite_wrapper (vt))
- {
- instance<object_columns> oc (model_, t);
- oc->traverse (m, *cvt, "value", "value");
- }
- else
- {
- instance<object_columns> oc (model_, t, "value");
- string const& name (column_name (m, "value", "value"));
- oc->traverse_column (m, name, true);
- }
- }
+ instance<object_columns> oc (model_, t);
+ oc->traverse (m, container_it (ct), "index", "index");
- // Create indexes.
- //
- using sema_rel::index;
- using sema_rel::column;
+ string col_name (column_name (m, "index", "index"));
- {
- index& i (model_.new_node<index> (id + ".id"));
- i.set ("cxx-node", static_cast<semantics::node*> (&m));
+ index& in (model_.new_node<index> (id + ".index"));
+ in.set ("cxx-node", static_cast<semantics::node*> (&m));
model_.new_edge<sema_rel::contains> (
- i, dynamic_cast<column&> (t.find (id_name)->nameable ()));
+ in, dynamic_cast<column&> (t.find (col_name)->nameable ()));
- //@@ Once id can be composite, we need to revise this (see
- // a comment for the foreign key generation above).
- //
model_.new_edge<sema_rel::qnames> (
- model_, i, name + "_" + id_name + "_i");
+ model_, in, name + "_" + col_name + "_i");
}
- if (ordered)
+ // key
+ //
+ if (ck == ck_map || ck == ck_multimap)
{
- index& i (model_.new_node<index> (id + ".index"));
- i.set ("cxx-node", static_cast<semantics::node*> (&m));
-
- model_.new_edge<sema_rel::contains> (
- i, dynamic_cast<column&> (t.find (index_name)->nameable ()));
+ instance<object_columns> oc (model_, t);
+ oc->traverse (m, container_kt (ct), "key", "key");
+ }
- // This is always a single column (simple value).
- //
- model_.new_edge<sema_rel::qnames> (
- model_, i, name + "_" + index_name + "_i");
+ // value
+ //
+ {
+ instance<object_columns> oc (model_, t);
+ oc->traverse (m, container_vt (ct), "value", "value");
}
}
diff --git a/odb/relational/mssql/common.cxx b/odb/relational/mssql/common.cxx
index f4ce42e..20be733 100644
--- a/odb/relational/mssql/common.cxx
+++ b/odb/relational/mssql/common.cxx
@@ -16,91 +16,10 @@ namespace relational
// member_base
//
- void member_base::
- traverse (semantics::data_member& m)
+ sql_type const& member_base::
+ member_sql_type (semantics::data_member& m)
{
- if (transient (m))
- return;
-
- string var;
-
- if (!var_override_.empty ())
- var = var_override_;
- else
- {
- string const& name (m.name ());
- var = name + (name[name.size () - 1] == '_' ? "" : "_");
- }
-
- bool cq (type_override_ != 0 ? false : const_type (m.type ()));
- semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m));
-
- semantics::type* cont;
- if (semantics::class_* c = composite_wrapper (t))
- {
- // If t is a wrapper, pass the wrapped type. Also pass the
- // original, wrapper type.
- //
- member_info mi (m,
- *c,
- (wrapper (t) ? &t : 0),
- cq,
- var,
- fq_type_override_);
- if (pre (mi))
- {
- traverse_composite (mi);
- post (mi);
- }
- }
- // This cannot be a container if we have a type override.
- //
- else if (type_override_ == 0 && (cont = context::container (m)))
- {
- // The same unwrapping logic as for composite values.
- //
- member_info mi (m,
- *cont,
- (wrapper (t) ? &t : 0),
- cq,
- var,
- fq_type_override_);
- if (pre (mi))
- {
- traverse_container (mi);
- post (mi);
- }
- }
- else
- {
- sql_type const& st (column_sql_type (m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (t))
- {
- member_info mi (m,
- utype (*id_member (*c)),
- 0,
- cq,
- var,
- fq_type_override_);
- mi.st = &st;
- if (pre (mi))
- {
- traverse_object_pointer (mi);
- post (mi);
- }
- }
- else
- {
- member_info mi (m, t, 0, cq, var, fq_type_override_);
- mi.st = &st;
- if (pre (mi))
- {
- traverse_simple (mi);
- post (mi);
- }
- }
- }
+ return parse_sql_type (column_type (m, key_prefix_), m);
}
void member_base::
@@ -406,15 +325,23 @@ namespace relational
};
member_database_type_id::
+ member_database_type_id (base const& x)
+ : member_base::base (x), // virtual base
+ base (x)
+ {
+ }
+
+ member_database_type_id::
member_database_type_id (semantics::type* type,
string const& fq_type,
string const& key_prefix)
- : relational::member_base (type, fq_type, key_prefix)
+ : member_base::base (type, fq_type, key_prefix), // virtual base
+ base (type, fq_type, key_prefix)
{
}
string member_database_type_id::
- database_type_id (type& m)
+ database_type_id (semantics::data_member& m)
{
type_id_.clear ();
member_base::traverse (m);
@@ -535,6 +462,8 @@ namespace relational
type_id_ = "mssql::id_rowversion";
}
+ entry<member_database_type_id> member_database_type_id_;
+
//
// query_columns
//
@@ -566,7 +495,7 @@ namespace relational
{
// For some types we need to pass precision and scale.
//
- sql_type const& st (column_sql_type (m));
+ sql_type const& st (parse_sql_type (column_type (), m));
switch (st.type)
{
diff --git a/odb/relational/mssql/common.hxx b/odb/relational/mssql/common.hxx
index 7f2009a..a04c9a3 100644
--- a/odb/relational/mssql/common.hxx
+++ b/odb/relational/mssql/common.hxx
@@ -12,118 +12,18 @@ namespace relational
{
namespace mssql
{
- struct member_base: virtual relational::member_base, context
+ struct member_base: virtual relational::member_base_impl<sql_type>, context
{
- member_base (base const& x): base (x) {}
+ member_base (base const& x): base (x), base_impl (x) {}
// This c-tor is for the direct use inside the mssql namespace.
// If you do use this c-tor, you should also explicitly call
- // relational::member_base.
+ // relational::member_base (aka base).
//
member_base () {}
- virtual void
- traverse (semantics::data_member& m);
-
- struct member_info
- {
- semantics::data_member& m; // Member.
- semantics::type& t; // Cvr-unqualified member C++ type, note
- // that m.type () may not be the same as t.
- semantics::type* wrapper; // Wrapper type if member is a composite or
- // container wrapper, also cvr-unqualified.
- // In this case t is the wrapped type.
- bool cq; // True if the original (wrapper) type
- // is const-qualified.
- sql_type const* st; // Member SQL type (only simple values).
- string& var; // Member variable name with trailing '_'.
-
- // C++ type fq-name.
- //
- string
- fq_type (bool unwrap = true) const
- {
- semantics::names* hint;
-
- if (wrapper != 0 && unwrap)
- {
- // Use the hint from the wrapper unless the wrapped type
- // is qualified.
- //
- hint = wrapper->get<semantics::names*> ("wrapper-hint");
- utype (*context::wrapper (*wrapper), hint);
- return t.fq_name (hint);
- }
-
- // Use the original type from 'm' instead of 't' since the hint
- // may be invalid for a different type. Plus, if a type is
- // overriden, then the fq_type must be as well.
- //
- if (fq_type_.empty ())
- {
- semantics::type& t (utype (m, hint));
- return t.fq_name (hint);
- }
- else
- return fq_type_;
- }
-
- string const& fq_type_;
-
- member_info (semantics::data_member& m_,
- semantics::type& t_,
- semantics::type* wrapper_,
- bool cq_,
- string& var_,
- string const& fq_type)
- : m (m_),
- t (t_),
- wrapper (wrapper_),
- cq (cq_),
- st (0),
- var (var_),
- fq_type_ (fq_type)
- {
- }
- };
-
- bool
- container (member_info& mi)
- {
- // This cannot be a container if we have a type override.
- //
- return type_override_ == 0 && context::container (mi.m);
- }
-
- // The false return value indicates that no further callbacks
- // should be called for this member.
- //
- virtual bool
- pre (member_info&)
- {
- return true;
- }
-
- virtual void
- post (member_info&)
- {
- }
-
- virtual void
- traverse_composite (member_info&)
- {
- }
-
- virtual void
- traverse_container (member_info&)
- {
- }
-
- virtual void
- traverse_object_pointer (member_info& mi)
- {
- traverse_simple (mi);
- }
+ virtual sql_type const&
+ member_sql_type (semantics::data_member&);
virtual void
traverse_simple (member_info&);
@@ -288,13 +188,17 @@ namespace relational
string type_;
};
- struct member_database_type_id: member_base
+ struct member_database_type_id: relational::member_database_type_id,
+ member_base
{
+ member_database_type_id (base const&);
+
member_database_type_id (semantics::type* type = 0,
string const& fq_type = string (),
string const& key_prefix = string ());
- string
- database_type_id (type&);
+
+ virtual string
+ database_type_id (semantics::data_member&);
virtual void
traverse_composite (member_info&);
@@ -361,13 +265,17 @@ namespace relational
{
has_long_data (bool& r): r_ (r) {}
+ 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&, bool)
{
- if (inverse (m))
- return false;
-
- sql_type const& st (column_sql_type (m));
+ sql_type const& st (parse_sql_type (column_type (), m));
switch (st.type)
{
diff --git a/odb/relational/mssql/context.cxx b/odb/relational/mssql/context.cxx
index e882ba3..312cc03 100644
--- a/odb/relational/mssql/context.cxx
+++ b/odb/relational/mssql/context.cxx
@@ -557,17 +557,20 @@ namespace relational
}
sql_type const& context::
- column_sql_type (semantics::data_member& m, string const& kp)
+ parse_sql_type (string const& t, semantics::data_member& m)
{
- string key (kp.empty ()
- ? string ("mssql-column-sql-type")
- : "mssql-" + kp + "-column-sql-type");
+ // If this proves to be too expensive, we can maintain a
+ // cache of parsed types.
+ //
+ data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t));
- if (!m.count (key))
+ if (i != data_->sql_type_cache_.end ())
+ return i->second;
+ else
{
try
{
- m.set (key, parse_sql_type (column_type (m, kp)));
+ return (data_->sql_type_cache_[t] = parse_sql_type (t));
}
catch (invalid_sql_type const& e)
{
@@ -577,8 +580,6 @@ namespace relational
throw operation_failed ();
}
}
-
- return m.get<sql_type> (key);
}
sql_type context::
diff --git a/odb/relational/mssql/context.hxx b/odb/relational/mssql/context.hxx
index 7530a9f..fe30746 100644
--- a/odb/relational/mssql/context.hxx
+++ b/odb/relational/mssql/context.hxx
@@ -5,6 +5,8 @@
#ifndef ODB_RELATIONAL_MSSQL_CONTEXT_HXX
#define ODB_RELATIONAL_MSSQL_CONTEXT_HXX
+#include <map>
+
#include <odb/relational/context.hxx>
namespace relational
@@ -83,8 +85,7 @@ namespace relational
{
public:
sql_type const&
- column_sql_type (semantics::data_member&,
- string const& key_prefix = string ());
+ parse_sql_type (string const&, semantics::data_member&);
public:
struct invalid_sql_type
@@ -132,6 +133,9 @@ namespace relational
struct data: base_context::data
{
data (std::ostream& os): base_context::data (os) {}
+
+ typedef std::map<string, sql_type> sql_type_cache;
+ sql_type_cache sql_type_cache_;
};
data* data_;
};
diff --git a/odb/relational/mssql/model.cxx b/odb/relational/mssql/model.cxx
index aec027c..c3f4948 100644
--- a/odb/relational/mssql/model.cxx
+++ b/odb/relational/mssql/model.cxx
@@ -28,7 +28,7 @@ namespace relational
{
// Make sure the column is mapped to an integer or DECIMAL type.
//
- switch (column_sql_type (m).type)
+ switch (parse_sql_type (column_type (), m).type)
{
case sql_type::BIT:
case sql_type::TINYINT:
diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx
index 1c11984..1b800aa 100644
--- a/odb/relational/mssql/source.cxx
+++ b/odb/relational/mssql/source.cxx
@@ -41,17 +41,16 @@ namespace relational
virtual void
column (semantics::data_member& m,
- string const& key_prefix,
string const& table,
string const& column)
{
// Don't add a column for auto id in the INSERT statement.
//
if (!(sk_ == statement_insert &&
- key_prefix.empty () &&
- id (m) && auto_(m)))
+ key_prefix_.empty () &&
+ context::id (m) && auto_(m))) // Only simple id can be auto.
{
- base::column (m, key_prefix, table, column);
+ base::column (m, table, column);
}
}
};
@@ -413,181 +412,21 @@ namespace relational
// init image
//
- struct init_image_member: relational::init_image_member, member_base
+ struct init_image_member: relational::init_image_member_impl<sql_type>,
+ member_base
{
init_image_member (base const& x)
- : member_base::base (x), // virtual base
- base (x),
- member_base (x),
- member_database_type_id_ (base::type_override_,
- base::fq_type_override_,
- base::key_prefix_)
- {
- }
-
- virtual bool
- pre (member_info& mi)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
{
- // 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 (!member_override_.empty ())
- member = member_override_;
- else
- {
- // If we are generating standard init() and this member
- // contains version, ignore it.
- //
- if (version (mi.m))
- return false;
-
- // For SQL Server we don't send auto id in INSERT statement
- // (nor in UPDATE, as for other databases). So ignore it
- // altogether.
- //
- if (id (mi.m) && auto_ (mi.m))
- return false;
-
- string const& name (mi.m.name ());
- member = "o." + name;
-
- os << "// " << name << endl
- << "//" << endl;
-
- // If the whole class is readonly, then we will never be
- // called with sk == statement_update.
- //
- if (!readonly (*context::top_object))
- {
- semantics::class_* c;
-
- if (id (mi.m) ||
- readonly (mi.m) ||
- ((c = composite (mi.t)) && readonly (*c)))
- os << "if (sk == statement_insert)";
- }
- }
-
- // If this is a wrapped composite value, then we need to
- // "unwrap" it. For simple values this is taken care of
- // by the value_traits specializations.
- //
- if (mi.wrapper != 0 && composite (mi.t))
- {
- // Here we need the wrapper type, not the wrapped type.
- //
- member = "wrapper_traits< " + mi.fq_type (false) + " >::" +
- "get_ref (" + member + ")";
- }
-
- if (composite (mi.t))
- {
- os << "{";
- traits = "composite_value_traits< " + mi.fq_type () + " >";
- }
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (mt))
- {
- type = "obj_traits::id_type";
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- // Handle NULL pointers and extract the id.
- //
- os << "{"
- << "typedef object_traits< " << class_fq_name (*c) <<
- " > obj_traits;";
-
- if (weak_pointer (mt))
- {
- os << "typedef pointer_traits< " << mi.fq_type () <<
- " > wptr_traits;"
- << "typedef 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 pointer_traits< " << mi.fq_type () <<
- " > ptr_traits;"
- << endl;
-
- os << "bool is_null (ptr_traits::null_ptr (" << member << "));"
- << "if (!is_null)"
- << "{"
- << "const " << type << "& id (" << endl;
-
- if (lazy_pointer (mt))
- os << "ptr_traits::object_id< ptr_traits::element_type > (" <<
- member << ")";
- else
- os << "obj_traits::id (ptr_traits::get_ref (" << member << "))";
-
- os << ");"
- << endl;
-
- member = "id";
- }
- else
- {
- type = mi.fq_type ();
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- os << "{"
- << "bool is_null;";
- }
-
- traits = "mssql::value_traits<\n "
- + type + ",\n "
- + db_type_id + " >";
- }
-
- return true;
}
virtual void
- post (member_info& mi)
+ set_null (member_info& mi)
{
- if (composite (mi.t))
- os << "}";
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- if (object_pointer (member_utype (mi.m, key_prefix_)))
- {
- os << "}"
- << "else" << endl;
-
- if (!null (mi.m, key_prefix_))
- os << "throw null_pointer ();";
- else
- os << "i." << mi.var << "size_ind = SQL_NULL_DATA;";
- }
-
- os << "}";
- }
- }
-
- virtual void
- traverse_composite (member_info& mi)
- {
- os << traits << "::init (" << endl
- << "i." << mi.var << "value," << endl
- << member << "," << endl
- << "sk);";
+ os << "i." << mi.var << "size_ind = SQL_NULL_DATA;";
}
virtual void
@@ -800,14 +639,6 @@ namespace relational
<< "i." << mi.var << "value, is_null, " << member << ");"
<< "i." << mi.var << "size_ind = is_null ? SQL_NULL_DATA : 8;";
}
-
- private:
- string type;
- string db_type_id;
- string member;
- string traits;
-
- member_database_type_id member_database_type_id_;
};
entry<init_image_member> init_image_member_;
@@ -815,147 +646,21 @@ namespace relational
// init value
//
- struct init_value_member: relational::init_value_member, member_base
+ struct init_value_member: relational::init_value_member_impl<sql_type>,
+ member_base
{
init_value_member (base const& x)
- : member_base::base (x), // virtual base
- base (x),
- member_base (x),
- member_database_type_id_ (base::type_override_,
- base::fq_type_override_,
- base::key_prefix_)
- {
- }
-
- virtual bool
- pre (member_info& mi)
- {
- if (container (mi))
- return false;
-
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- string const& name (mi.m.name ());
- member = "o." + name;
-
- if (mi.cq)
- member = "const_cast< " + mi.fq_type (false) + "& > (" +
- member + ")";
-
- os << "// " << name << endl
- << "//" << endl;
- }
-
- // If this is a wrapped composite value, then we need to
- // "unwrap" it. For simple values this is taken care of
- // by the value_traits specializations.
- //
- if (mi.wrapper != 0 && composite (mi.t))
- {
- // Here we need the wrapper type, not the wrapped type.
- //
- member = "wrapper_traits< " + mi.fq_type (false) + " >::" +
- "set_ref (\n" + member + ")";
- }
-
- if (composite (mi.t))
- traits = "composite_value_traits< " + mi.fq_type () + " >";
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (mt))
- {
- type = "obj_traits::id_type";
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- // Handle NULL pointers and extract the id.
- //
- os << "{"
- << "typedef object_traits< " << class_fq_name (*c) <<
- " > obj_traits;"
- << "typedef pointer_traits< " << mi.fq_type () <<
- " > ptr_traits;"
- << endl
- << "if (i." << mi.var << "size_ind == SQL_NULL_DATA)" << endl;
-
- if (null (mi.m, key_prefix_))
- os << member << " = ptr_traits::pointer_type ();";
- else
- os << "throw null_pointer ();";
-
- os << "else"
- << "{"
- << type << " id;";
-
- member = "id";
- }
- else
- {
- type = mi.fq_type ();
- db_type_id = member_database_type_id_.database_type_id (mi.m);
- }
-
- traits = "mssql::value_traits<\n "
- + type + ",\n "
- + db_type_id + " >";
- }
-
- return true;
- }
-
- virtual void
- post (member_info& mi)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
{
- if (composite (mi.t))
- return;
-
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (object_pointer (mt))
- {
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- member = "o." + mi.m.name ();
-
- if (mi.cq)
- member = "const_cast< " + mi.fq_type (false) + "& > (" +
- member + ")";
- }
-
- if (lazy_pointer (mt))
- os << member << " = ptr_traits::pointer_type (db, 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
- << "db.load< obj_traits::object_type > (id));";
-
- os << "}"
- << "}";
- }
}
virtual void
- traverse_composite (member_info& mi)
+ get_null (member_info& mi)
{
- os << traits << "::init (" << endl
- << member << "," << endl
- << "i." << mi.var << "value," << endl
- << "db);"
- << endl;
+ os << "i." << mi.var << "size_ind == SQL_NULL_DATA";
}
virtual void
@@ -1141,14 +846,6 @@ namespace relational
<< "i." << mi.var << "size_ind == SQL_NULL_DATA);"
<< endl;
}
-
- private:
- string type;
- string db_type_id;
- string traits;
- string member;
-
- member_database_type_id member_database_type_id_;
};
entry<init_value_member> init_value_member_;
@@ -1172,7 +869,7 @@ namespace relational
size_t n (cols.size ());
for (statement_columns::iterator i (cols.begin ()); n != 0; --n)
{
- sql_type const& st (column_sql_type (*i->member, i->key_prefix));
+ sql_type const& st (parse_sql_type (i->type, *i->member));
bool l (false);
diff --git a/odb/relational/mysql/common.cxx b/odb/relational/mysql/common.cxx
index c8bad12..b8fa4c3 100644
--- a/odb/relational/mysql/common.cxx
+++ b/odb/relational/mysql/common.cxx
@@ -16,91 +16,10 @@ namespace relational
// member_base
//
- void member_base::
- traverse (semantics::data_member& m)
+ sql_type const& member_base::
+ member_sql_type (semantics::data_member& m)
{
- if (transient (m))
- return;
-
- string var;
-
- if (!var_override_.empty ())
- var = var_override_;
- else
- {
- string const& name (m.name ());
- var = name + (name[name.size () - 1] == '_' ? "" : "_");
- }
-
- bool cq (type_override_ != 0 ? false : const_type (m.type ()));
- semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m));
-
- semantics::type* cont;
- if (semantics::class_* c = composite_wrapper (t))
- {
- // If t is a wrapper, pass the wrapped type. Also pass the
- // original, wrapper type.
- //
- member_info mi (m,
- *c,
- (wrapper (t) ? &t : 0),
- cq,
- var,
- fq_type_override_);
- if (pre (mi))
- {
- traverse_composite (mi);
- post (mi);
- }
- }
- // This cannot be a container if we have a type override.
- //
- else if (type_override_ == 0 && (cont = context::container (m)))
- {
- // The same unwrapping logic as for composite values.
- //
- member_info mi (m,
- *cont,
- (wrapper (t) ? &t : 0),
- cq,
- var,
- fq_type_override_);
- if (pre (mi))
- {
- traverse_container (mi);
- post (mi);
- }
- }
- else
- {
- sql_type const& st (column_sql_type (m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (t))
- {
- member_info mi (m,
- utype (*id_member (*c)),
- 0,
- cq,
- var,
- fq_type_override_);
- mi.st = &st;
- if (pre (mi))
- {
- traverse_object_pointer (mi);
- post (mi);
- }
- }
- else
- {
- member_info mi (m, t, 0, cq, var, fq_type_override_);
- mi.st = &st;
- if (pre (mi))
- {
- traverse_simple (mi);
- post (mi);
- }
- }
- }
+ return parse_sql_type (column_type (m, key_prefix_), m);
}
void member_base::
@@ -363,10 +282,18 @@ namespace relational
};
member_database_type_id::
+ member_database_type_id (base const& x)
+ : member_base::base (x), // virtual base
+ base (x)
+ {
+ }
+
+ member_database_type_id::
member_database_type_id (semantics::type* type,
- string const& fq_type,
- string const& key_prefix)
- : relational::member_base (type, fq_type, key_prefix)
+ string const& fq_type,
+ string const& key_prefix)
+ : member_base::base (type, fq_type, key_prefix), // virtual base
+ base (type, fq_type, key_prefix)
{
}
@@ -437,6 +364,8 @@ namespace relational
type_id_ = "mysql::id_set";
}
+ entry<member_database_type_id> member_database_type_id_;
+
//
// query_columns
//
diff --git a/odb/relational/mysql/common.hxx b/odb/relational/mysql/common.hxx
index c49bd09..93f5fbd 100644
--- a/odb/relational/mysql/common.hxx
+++ b/odb/relational/mysql/common.hxx
@@ -12,118 +12,18 @@ namespace relational
{
namespace mysql
{
- struct member_base: virtual relational::member_base, context
+ struct member_base: virtual relational::member_base_impl<sql_type>, context
{
- member_base (base const& x): base (x) {}
+ member_base (base const& x): base (x), base_impl (x) {}
// This c-tor is for the direct use inside the mysql namespace.
// If you do use this c-tor, you should also explicitly call
- // relational::member_base.
+ // relational::member_base (aka base).
//
member_base () {}
- virtual void
- traverse (semantics::data_member& m);
-
- struct member_info
- {
- semantics::data_member& m; // Member.
- semantics::type& t; // Cvr-unqualified member C++ type, note
- // that m.type () may not be the same as t.
- semantics::type* wrapper; // Wrapper type if member is a composite or
- // container wrapper, also cvr-unqualified.
- // In this case t is the wrapped type.
- bool cq; // True if the original (wrapper) type
- // is const-qualified.
- sql_type const* st; // Member SQL type (only simple values).
- string& var; // Member variable name with trailing '_'.
-
- // C++ type fq-name.
- //
- string
- fq_type (bool unwrap = true) const
- {
- semantics::names* hint;
-
- if (wrapper != 0 && unwrap)
- {
- // Use the hint from the wrapper unless the wrapped type
- // is qualified.
- //
- hint = wrapper->get<semantics::names*> ("wrapper-hint");
- utype (*context::wrapper (*wrapper), hint);
- return t.fq_name (hint);
- }
-
- // Use the original type from 'm' instead of 't' since the hint
- // may be invalid for a different type. Plus, if a type is
- // overriden, then the fq_type must be as well.
- //
- if (fq_type_.empty ())
- {
- semantics::type& t (utype (m, hint));
- return t.fq_name (hint);
- }
- else
- return fq_type_;
- }
-
- string const& fq_type_;
-
- member_info (semantics::data_member& m_,
- semantics::type& t_,
- semantics::type* wrapper_,
- bool cq_,
- string& var_,
- string const& fq_type)
- : m (m_),
- t (t_),
- wrapper (wrapper_),
- cq (cq_),
- st (0),
- var (var_),
- fq_type_ (fq_type)
- {
- }
- };
-
- bool
- container (member_info& mi)
- {
- // This cannot be a container if we have a type override.
- //
- return type_override_ == 0 && context::container (mi.m);
- }
-
- // The false return value indicates that no further callbacks
- // should be called for this member.
- //
- virtual bool
- pre (member_info&)
- {
- return true;
- }
-
- virtual void
- post (member_info&)
- {
- }
-
- virtual void
- traverse_composite (member_info&)
- {
- }
-
- virtual void
- traverse_container (member_info&)
- {
- }
-
- virtual void
- traverse_object_pointer (member_info& mi)
- {
- traverse_simple (mi);
- }
+ virtual sql_type const&
+ member_sql_type (semantics::data_member&);
virtual void
traverse_simple (member_info&);
@@ -220,12 +120,16 @@ namespace relational
string type_;
};
- struct member_database_type_id: member_base
+ struct member_database_type_id: relational::member_database_type_id,
+ member_base
{
+ member_database_type_id (base const&);
+
member_database_type_id (semantics::type* type = 0,
string const& fq_type = string (),
string const& key_prefix = string ());
- string
+
+ virtual string
database_type_id (type&);
virtual void
diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx
index b8327eb..ad7236c 100644
--- a/odb/relational/mysql/context.cxx
+++ b/odb/relational/mysql/context.cxx
@@ -316,17 +316,20 @@ namespace relational
//
sql_type const& context::
- column_sql_type (semantics::data_member& m, string const& kp)
+ parse_sql_type (string const& t, semantics::data_member& m)
{
- string key (kp.empty ()
- ? string ("mysql-column-sql-type")
- : "mysql-" + kp + "-column-sql-type");
+ // If this proves to be too expensive, we can maintain a
+ // cache of parsed types.
+ //
+ data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t));
- if (!m.count (key))
+ if (i != data_->sql_type_cache_.end ())
+ return i->second;
+ else
{
try
{
- m.set (key, parse_sql_type (column_type (m, kp)));
+ return (data_->sql_type_cache_[t] = parse_sql_type (t));
}
catch (invalid_sql_type const& e)
{
@@ -336,8 +339,6 @@ namespace relational
throw operation_failed ();
}
}
-
- return m.get<sql_type> (key);
}
sql_type context::
diff --git a/odb/relational/mysql/context.hxx b/odb/relational/mysql/context.hxx
index 49b825e..294b5d1 100644
--- a/odb/relational/mysql/context.hxx
+++ b/odb/relational/mysql/context.hxx
@@ -5,6 +5,7 @@
#ifndef ODB_RELATIONAL_MYSQL_CONTEXT_HXX
#define ODB_RELATIONAL_MYSQL_CONTEXT_HXX
+#include <map>
#include <vector>
#include <odb/relational/context.hxx>
@@ -80,8 +81,7 @@ namespace relational
{
public:
sql_type const&
- column_sql_type (semantics::data_member&,
- string const& key_prefix = string ());
+ parse_sql_type (string const&, semantics::data_member&);
public:
struct invalid_sql_type
@@ -138,6 +138,9 @@ namespace relational
struct data: base_context::data
{
data (std::ostream& os): base_context::data (os) {}
+
+ typedef std::map<string, sql_type> sql_type_cache;
+ sql_type_cache sql_type_cache_;
};
data* data_;
};
diff --git a/odb/relational/mysql/model.cxx b/odb/relational/mysql/model.cxx
index 8e07f38..11ca157 100644
--- a/odb/relational/mysql/model.cxx
+++ b/odb/relational/mysql/model.cxx
@@ -35,7 +35,7 @@ namespace relational
{
// Make sure the column is mapped to an ENUM or integer type.
//
- sql_type const& t (column_sql_type (m));
+ sql_type const& t (parse_sql_type (column_type (), m));
switch (t.type)
{
diff --git a/odb/relational/mysql/source.cxx b/odb/relational/mysql/source.cxx
index 91b3061..3a784af 100644
--- a/odb/relational/mysql/source.cxx
+++ b/odb/relational/mysql/source.cxx
@@ -68,7 +68,6 @@ namespace relational
virtual void
column (semantics::data_member& m,
- string const& key_prefix,
string const& table,
string const& column)
{
@@ -110,10 +109,12 @@ namespace relational
// to value_traits.
//
+ string type (column_type ());
+
if (sk_ != statement_select ||
- column_sql_type (m, key_prefix).type != sql_type::ENUM)
+ parse_sql_type (type, m).type != sql_type::ENUM)
{
- base::column (m, key_prefix, table, column);
+ base::column (m, table, column);
return;
}
@@ -140,7 +141,8 @@ namespace relational
r += ")";
- sc_.push_back (relational::statement_column (r, m, key_prefix));
+ sc_.push_back (
+ relational::statement_column (r, type, m, key_prefix_));
}
};
entry<object_columns> object_columns_;
@@ -154,7 +156,9 @@ namespace relational
{
// The same idea as in object_columns.
//
- if (column_sql_type (m).type != sql_type::ENUM)
+ string type (column_type ());
+
+ if (parse_sql_type (type, m).type != sql_type::ENUM)
{
base::column (m, column);
return;
@@ -168,7 +172,7 @@ namespace relational
r += column;
r += ")";
- sc_.push_back (relational::statement_column (r, m));
+ sc_.push_back (relational::statement_column (r, type, m));
}
};
entry<view_columns> view_columns_;
@@ -568,188 +572,37 @@ namespace relational
// init image
//
- struct init_image_member: relational::init_image_member, member_base
+ struct init_image_member: relational::init_image_member_impl<sql_type>,
+ member_base
{
init_image_member (base const& x)
- : member_base::base (x), // virtual base
- base (x),
- member_base (x),
- member_database_type_id_ (base::type_override_,
- base::fq_type_override_,
- base::key_prefix_)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
{
}
- 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 (!member_override_.empty ())
- member = member_override_;
- else
- {
- // If we are generating standard init() and this member
- // contains version, ignore it.
- //
- if (version (mi.m))
- return false;
-
- string const& name (mi.m.name ());
- member = "o." + name;
-
- os << "// " << name << endl
- << "//" << endl;
-
- // If the whole class is readonly, then we will never be
- // called with sk == statement_update.
- //
- if (!readonly (*context::top_object))
- {
- semantics::class_* c;
-
- if (id (mi.m) ||
- readonly (mi.m) ||
- ((c = composite (mi.t)) && readonly (*c)))
- os << "if (sk == statement_insert)";
- }
- }
-
- // If this is a wrapped composite value, then we need to
- // "unwrap" it. For simple values this is taken care of
- // by the value_traits specializations.
- //
- if (mi.wrapper != 0 && composite (mi.t))
- {
- // Here we need the wrapper type, not the wrapped type.
- //
- member = "wrapper_traits< " + mi.fq_type (false) + " >::" +
- "get_ref (" + member + ")";
- }
-
- if (composite (mi.t))
- {
- os << "{";
- traits = "composite_value_traits< " + mi.fq_type () + " >";
- }
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (mt))
- {
- type = "obj_traits::id_type";
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- // Handle NULL pointers and extract the id.
- //
- os << "{"
- << "typedef object_traits< " << class_fq_name (*c) <<
- " > obj_traits;";
-
- if (weak_pointer (mt))
- {
- os << "typedef pointer_traits< " << mi.fq_type () <<
- " > wptr_traits;"
- << "typedef 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 pointer_traits< " << mi.fq_type () <<
- " > ptr_traits;"
- << endl;
-
- os << "bool is_null (ptr_traits::null_ptr (" << member << "));"
- << "if (!is_null)"
- << "{"
- << "const " << type << "& id (" << endl;
-
- if (lazy_pointer (mt))
- os << "ptr_traits::object_id< ptr_traits::element_type > (" <<
- member << ")";
- else
- os << "obj_traits::id (ptr_traits::get_ref (" << member << "))";
-
- os << ");"
- << endl;
-
- member = "id";
- }
- else
- {
- type = mi.fq_type ();
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- os << "{"
- << "bool is_null;";
- }
-
- traits = "mysql::value_traits<\n "
- + type + ",\n "
- + db_type_id + " >";
- }
-
- return true;
- }
-
virtual void
- post (member_info& mi)
+ set_null (member_info& mi)
{
- if (composite (mi.t))
- os << "}";
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- if (object_pointer (member_utype (mi.m, key_prefix_)))
- {
- os << "}";
-
- if (!null (mi.m, key_prefix_))
- os << "else" << endl
- << "throw null_pointer ();";
- }
-
- os << "i." << mi.var << "null = is_null;"
- << "}";
- }
- }
-
- virtual void
- traverse_composite (member_info& mi)
- {
- os << "if (" << traits << "::init (" << endl
- << "i." << mi.var << "value," << endl
- << member << "," << endl
- << "sk))" << endl
- << "grew = true;";
+ os << "i." << mi.var << "null = 1;";
}
virtual void
traverse_integer (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "null = is_null;";
}
virtual void
traverse_float (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "null = is_null;";
}
virtual void
@@ -764,6 +617,7 @@ namespace relational
<< "size," << endl
<< "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "i." << mi.var << "size = static_cast<unsigned long> (size);"
<< "grew = grew || (cap != i." << mi.var << "value.capacity ());";
}
@@ -772,7 +626,8 @@ namespace relational
traverse_date_time (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "null = is_null;";
}
virtual void
@@ -787,6 +642,7 @@ namespace relational
<< "size," << endl
<< "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "i." << mi.var << "size = static_cast<unsigned long> (size);"
<< "grew = grew || (cap != i." << mi.var << "value.capacity ());";
}
@@ -801,6 +657,7 @@ namespace relational
<< "size," << endl
<< "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "i." << mi.var << "size = static_cast<unsigned long> (size);"
<< "grew = grew || (cap != i." << mi.var << "value.capacity ());";
}
@@ -817,6 +674,7 @@ namespace relational
<< "size," << endl
<< "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "i." << mi.var << "size = static_cast<unsigned long> (size);";
}
@@ -830,7 +688,9 @@ namespace relational
<< "i." << mi.var << "size," << endl
<< "is_null," << endl
<< member << "))" << endl
- << "grew = true;";
+ << "grew = true;"
+ << endl
+ << "i." << mi.var << "null = is_null;";
}
virtual void
@@ -845,17 +705,10 @@ namespace relational
<< "size," << endl
<< "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "i." << mi.var << "size = static_cast<unsigned long> (size);"
<< "grew = grew || (cap != i." << mi.var << "value.capacity ());";
}
-
- private:
- string type;
- string db_type_id;
- string member;
- string traits;
-
- member_database_type_id member_database_type_id_;
};
entry<init_image_member> init_image_member_;
@@ -863,147 +716,21 @@ namespace relational
// init value
//
- struct init_value_member: relational::init_value_member, member_base
+ struct init_value_member: relational::init_value_member_impl<sql_type>,
+ member_base
{
init_value_member (base const& x)
- : member_base::base (x), // virtual base
- base (x),
- member_base (x),
- member_database_type_id_ (base::type_override_,
- base::fq_type_override_,
- base::key_prefix_)
- {
- }
-
- virtual bool
- pre (member_info& mi)
- {
- if (container (mi))
- return false;
-
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- string const& name (mi.m.name ());
- member = "o." + name;
-
- if (mi.cq)
- member = "const_cast< " + mi.fq_type (false) + "& > (" +
- member + ")";
-
- os << "// " << name << endl
- << "//" << endl;
- }
-
- // If this is a wrapped composite value, then we need to
- // "unwrap" it. For simple values this is taken care of
- // by the value_traits specializations.
- //
- if (mi.wrapper != 0 && composite (mi.t))
- {
- // Here we need the wrapper type, not the wrapped type.
- //
- member = "wrapper_traits< " + mi.fq_type (false) + " >::" +
- "set_ref (\n" + member + ")";
- }
-
- if (composite (mi.t))
- traits = "composite_value_traits< " + mi.fq_type () + " >";
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (mt))
- {
- type = "obj_traits::id_type";
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- // Handle NULL pointers and extract the id.
- //
- os << "{"
- << "typedef object_traits< " << class_fq_name (*c) <<
- " > obj_traits;"
- << "typedef pointer_traits< " << mi.fq_type () <<
- " > ptr_traits;"
- << endl
- << "if (i." << mi.var << "null)" << endl;
-
- if (null (mi.m, key_prefix_))
- os << member << " = ptr_traits::pointer_type ();";
- else
- os << "throw null_pointer ();";
-
- os << "else"
- << "{"
- << type << " id;";
-
- member = "id";
- }
- else
- {
- type = mi.fq_type ();
- db_type_id = member_database_type_id_.database_type_id (mi.m);
- }
-
- traits = "mysql::value_traits<\n "
- + type + ",\n "
- + db_type_id + " >";
- }
-
- return true;
- }
-
- virtual void
- post (member_info& mi)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
{
- if (composite (mi.t))
- return;
-
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (object_pointer (mt))
- {
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- member = "o." + mi.m.name ();
-
- if (mi.cq)
- member = "const_cast< " + mi.fq_type (false) + "& > (" +
- member + ")";
- }
-
- if (lazy_pointer (mt))
- os << member << " = ptr_traits::pointer_type (db, 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
- << "db.load< obj_traits::object_type > (id));";
-
- os << "}"
- << "}";
- }
}
virtual void
- traverse_composite (member_info& mi)
+ get_null (member_info& mi)
{
- os << traits << "::init (" << endl
- << member << "," << endl
- << "i." << mi.var << "value," << endl
- << "db);"
- << endl;
+ os << "i." << mi.var << "null";
}
virtual void
@@ -1107,14 +834,6 @@ namespace relational
<< "i." << mi.var << "null);"
<< endl;
}
-
- private:
- string type;
- string db_type_id;
- string traits;
- string member;
-
- member_database_type_id member_database_type_id_;
};
entry<init_value_member> init_value_member_;
diff --git a/odb/relational/oracle/common.cxx b/odb/relational/oracle/common.cxx
index 88183cf..661bb4e 100644
--- a/odb/relational/oracle/common.cxx
+++ b/odb/relational/oracle/common.cxx
@@ -16,91 +16,10 @@ namespace relational
// member_base
//
- void member_base::
- traverse (semantics::data_member& m)
+ sql_type const& member_base::
+ member_sql_type (semantics::data_member& m)
{
- if (transient (m))
- return;
-
- string var;
-
- if (!var_override_.empty ())
- var = var_override_;
- else
- {
- string const& name (m.name ());
- var = name + (name[name.size () - 1] == '_' ? "" : "_");
- }
-
- bool cq (type_override_ != 0 ? false : const_type (m.type ()));
- semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m));
-
- semantics::type* cont;
- if (semantics::class_* c = composite_wrapper (t))
- {
- // If t is a wrapper, pass the wrapped type. Also pass the
- // original, wrapper type.
- //
- member_info mi (m,
- *c,
- (wrapper (t) ? &t : 0),
- cq,
- var,
- fq_type_override_);
- if (pre (mi))
- {
- traverse_composite (mi);
- post (mi);
- }
- }
- // This cannot be a container if we have a type override.
- //
- else if (type_override_ == 0 && (cont = context::container (m)))
- {
- // The same unwrapping logic as for composite values.
- //
- member_info mi (m,
- *cont,
- (wrapper (t) ? &t : 0),
- cq,
- var,
- fq_type_override_);
- if (pre (mi))
- {
- traverse_container (mi);
- post (mi);
- }
- }
- else
- {
- sql_type const& st (column_sql_type (m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (t))
- {
- member_info mi (m,
- utype (*id_member (*c)),
- 0,
- cq,
- var,
- fq_type_override_);
- mi.st = &st;
- if (pre (mi))
- {
- traverse_object_pointer (mi);
- post (mi);
- }
- }
- else
- {
- member_info mi (m, t, 0, cq, var, fq_type_override_);
- mi.st = &st;
- if (pre (mi))
- {
- traverse_simple (mi);
- post (mi);
- }
- }
- }
+ return parse_sql_type (column_type (m, key_prefix_), m);
}
void member_base::
@@ -374,10 +293,18 @@ namespace relational
}
member_database_type_id::
+ member_database_type_id (base const& x)
+ : member_base::base (x), // virtual base
+ base (x)
+ {
+ }
+
+ member_database_type_id::
member_database_type_id (semantics::type* type,
string const& fq_type,
string const& key_prefix)
- : relational::member_base (type, fq_type, key_prefix)
+ : member_base::base (type, fq_type, key_prefix), // virtual base
+ base (type, fq_type, key_prefix)
{
}
@@ -469,6 +396,8 @@ namespace relational
lob_database_id[mi.st->type - sql_type::BLOB];
}
+ entry<member_database_type_id> member_database_type_id_;
+
//
// query_columns
//
@@ -494,7 +423,7 @@ namespace relational
{
// For some types we need to pass precision and scale.
//
- sql_type const& st (column_sql_type (m));
+ sql_type const& st (parse_sql_type (column_type (), m));
switch (st.type)
{
diff --git a/odb/relational/oracle/common.hxx b/odb/relational/oracle/common.hxx
index 0f4517d..15120fd 100644
--- a/odb/relational/oracle/common.hxx
+++ b/odb/relational/oracle/common.hxx
@@ -12,118 +12,18 @@ namespace relational
{
namespace oracle
{
- struct member_base: virtual relational::member_base, context
+ struct member_base: virtual relational::member_base_impl<sql_type>, context
{
- member_base (base const& x): base (x) {}
+ member_base (base const& x): base (x), base_impl (x) {}
// This c-tor is for the direct use inside the oracle namespace.
// If you do use this c-tor, you should also explicitly call
- // relational::member_base.
+ // relational::member_base (aka base).
//
member_base () {}
- virtual void
- traverse (semantics::data_member& m);
-
- struct member_info
- {
- semantics::data_member& m; // Member.
- semantics::type& t; // Cvr-unqualified member C++ type, note
- // that m.type () may not be the same as t.
- semantics::type* wrapper; // Wrapper type if member is a composite or
- // container wrapper, also cvr-unqualified.
- // In this case t is the wrapped type.
- bool cq; // True if the original (wrapper) type
- // is const-qualified.
- sql_type const* st; // Member SQL type (only simple values).
- string& var; // Member variable name with trailing '_'.
-
- // C++ type fq-name.
- //
- string
- fq_type (bool unwrap = true) const
- {
- semantics::names* hint;
-
- if (wrapper != 0 && unwrap)
- {
- // Use the hint from the wrapper unless the wrapped type
- // is qualified.
- //
- hint = wrapper->get<semantics::names*> ("wrapper-hint");
- utype (*context::wrapper (*wrapper), hint);
- return t.fq_name (hint);
- }
-
- // Use the original type from 'm' instead of 't' since the hint
- // may be invalid for a different type. Plus, if a type is
- // overriden, then the fq_type must be as well.
- //
- if (fq_type_.empty ())
- {
- semantics::type& t (utype (m, hint));
- return t.fq_name (hint);
- }
- else
- return fq_type_;
- }
-
- string const& fq_type_;
-
- member_info (semantics::data_member& m_,
- semantics::type& t_,
- semantics::type* wrapper_,
- bool cq_,
- string& var_,
- string const& fq_type)
- : m (m_),
- t (t_),
- wrapper (wrapper_),
- cq (cq_),
- st (0),
- var (var_),
- fq_type_ (fq_type)
- {
- }
- };
-
- bool
- container (member_info& mi)
- {
- // This cannot be a container if we have a type override.
- //
- return type_override_ == 0 && context::container (mi.m);
- }
-
- // The false return value indicates that no further callbacks
- // should be called for this member.
- //
- virtual bool
- pre (member_info&)
- {
- return true;
- }
-
- virtual void
- post (member_info&)
- {
- }
-
- virtual void
- traverse_composite (member_info&)
- {
- }
-
- virtual void
- traverse_container (member_info&)
- {
- }
-
- virtual void
- traverse_object_pointer (member_info& mi)
- {
- traverse_simple (mi);
- }
+ virtual sql_type const&
+ member_sql_type (semantics::data_member&);
virtual void
traverse_simple (member_info&);
@@ -240,12 +140,16 @@ namespace relational
string type_;
};
- struct member_database_type_id: member_base
+ struct member_database_type_id: relational::member_database_type_id,
+ member_base
{
+ member_database_type_id (base const&);
+
member_database_type_id (semantics::type* type = 0,
string const& fq_type = string (),
string const& key_prefix = string ());
- string
+
+ virtual string
database_type_id (type&);
virtual void
diff --git a/odb/relational/oracle/context.cxx b/odb/relational/oracle/context.cxx
index 3d87729..dbe61af 100644
--- a/odb/relational/oracle/context.cxx
+++ b/odb/relational/oracle/context.cxx
@@ -159,17 +159,20 @@ namespace relational
//
sql_type const& context::
- column_sql_type (semantics::data_member& m, string const& kp)
+ parse_sql_type (string const& t, semantics::data_member& m)
{
- string key (kp.empty ()
- ? string ("oracle-column-sql-type")
- : "oracle-" + kp + "-column-sql-type");
+ // If this proves to be too expensive, we can maintain a
+ // cache of parsed types.
+ //
+ data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t));
- if (!m.count (key))
+ if (i != data_->sql_type_cache_.end ())
+ return i->second;
+ else
{
try
{
- m.set (key, parse_sql_type (column_type (m, kp)));
+ return (data_->sql_type_cache_[t] = parse_sql_type (t));
}
catch (invalid_sql_type const& e)
{
@@ -179,8 +182,6 @@ namespace relational
throw operation_failed ();
}
}
-
- return m.get<sql_type> (key);
}
sql_type context::
diff --git a/odb/relational/oracle/context.hxx b/odb/relational/oracle/context.hxx
index 273f0e5..37716f0 100644
--- a/odb/relational/oracle/context.hxx
+++ b/odb/relational/oracle/context.hxx
@@ -5,6 +5,8 @@
#ifndef ODB_RELATIONAL_ORACLE_CONTEXT_HXX
#define ODB_RELATIONAL_ORACLE_CONTEXT_HXX
+#include <map>
+
#include <odb/relational/context.hxx>
namespace relational
@@ -73,8 +75,7 @@ namespace relational
{
public:
sql_type const&
- column_sql_type (semantics::data_member&,
- string const& key_prefix = string ());
+ parse_sql_type (string const&, semantics::data_member&);
public:
struct invalid_sql_type
@@ -126,6 +127,9 @@ namespace relational
struct data: base_context::data
{
data (std::ostream& os): base_context::data (os) {}
+
+ typedef std::map<string, sql_type> sql_type_cache;
+ sql_type_cache sql_type_cache_;
};
data* data_;
};
diff --git a/odb/relational/oracle/model.cxx b/odb/relational/oracle/model.cxx
index 347ea37..4b874c8 100644
--- a/odb/relational/oracle/model.cxx
+++ b/odb/relational/oracle/model.cxx
@@ -28,9 +28,7 @@ namespace relational
{
// Make sure the column is mapped to Oracle NUMBER.
//
- sql_type t (column_sql_type (m));
-
- if (t.type != sql_type::NUMBER)
+ if (parse_sql_type (column_type (), m).type != sql_type::NUMBER)
{
cerr << m.file () << ":" << m.line () << ":" << m.column ()
<< ": error: column with default value specified as C++ "
diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx
index fb0984a..1d7d81f 100644
--- a/odb/relational/oracle/source.cxx
+++ b/odb/relational/oracle/source.cxx
@@ -316,187 +316,37 @@ namespace relational
// init image
//
- struct init_image_member: relational::init_image_member, member_base
+ struct init_image_member: relational::init_image_member_impl<sql_type>,
+ member_base
{
init_image_member (base const& x)
- : member_base::base (x), // virtual base
- base (x),
- member_base (x),
- member_database_type_id_ (base::type_override_,
- base::fq_type_override_,
- base::key_prefix_)
- {
- }
-
- 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 (!member_override_.empty ())
- member = member_override_;
- else
- {
- // If we are generating standard init() and this member
- // contains version, ignore it.
- //
- if (version (mi.m))
- return false;
-
- string const& name (mi.m.name ());
- member = "o." + name;
-
- os << "// " << name << endl
- << "//" << endl;
-
- // If the whole class is readonly, then we will never be
- // called with sk == statement_update.
- //
- if (!readonly (*context::top_object))
- {
- semantics::class_* c;
-
- if (id (mi.m) ||
- readonly (mi.m) ||
- ((c = composite (mi.t)) && readonly (*c)))
- os << "if (sk == statement_insert)";
- }
- }
-
- // If this is a wrapped composite value, then we need to
- // "unwrap" it. For simple values this is taken care of
- // by the value_traits specializations.
- //
- if (mi.wrapper != 0 && composite (mi.t))
- {
- // Here we need the wrapper type, not the wrapped type.
- //
- member = "wrapper_traits< " + mi.fq_type (false) + " >::" +
- "get_ref (" + member + ")";
- }
-
- if (composite (mi.t))
- {
- os << "{";
- traits = "composite_value_traits< " + mi.fq_type () + " >";
- }
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (mt))
- {
- type = "obj_traits::id_type";
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- // Handle NULL pointers and extract the id.
- //
- os << "{"
- << "typedef object_traits< " << class_fq_name (*c) <<
- " > obj_traits;";
-
- if (weak_pointer (mt))
- {
- os << "typedef pointer_traits< " << mi.fq_type () <<
- " > wptr_traits;"
- << "typedef 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 pointer_traits< " << mi.fq_type () <<
- " > ptr_traits;"
- << endl;
-
- os << "bool is_null (ptr_traits::null_ptr (" << member << "));"
- << "if (!is_null)"
- << "{"
- << "const " << type << "& id (" << endl;
-
- if (lazy_pointer (mt))
- os << "ptr_traits::object_id< ptr_traits::element_type > (" <<
- member << ")";
- else
- os << "obj_traits::id (ptr_traits::get_ref (" << member << "))";
-
- os << ");"
- << endl;
-
- member = "id";
- }
- else
- {
- type = mi.fq_type ();
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- os << "{"
- << "bool is_null;";
- }
-
- traits = "oracle::value_traits<\n "
- + type + ",\n "
- + db_type_id + " >";
- }
-
- return true;
- }
-
- virtual void
- post (member_info& mi)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
{
- if (composite (mi.t))
- os << "}";
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- if (object_pointer (member_utype (mi.m, key_prefix_)))
- {
- os << "}";
-
- if (!null (mi.m, key_prefix_))
- os << "else" << endl
- << "throw null_pointer ();";
- }
-
- os << "i." << mi.var << "indicator = is_null ? -1 : 0;"
- << "}";
- }
}
virtual void
- traverse_composite (member_info& mi)
+ set_null (member_info& mi)
{
- os << traits << "::init (" << endl
- << "i." << mi.var << "value," << endl
- << member << "," << endl
- << "sk);";
+ os << "i." << mi.var << "indicator = -1;";
}
virtual void
traverse_int32 (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "indicator = is_null ? -1 : 0;";
}
virtual void
traverse_int64 (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "indicator = is_null ? -1 : 0;";
}
virtual void
@@ -508,6 +358,7 @@ namespace relational
<< "size," << endl
<< "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "indicator = is_null ? -1 : 0;"
<< "i." << mi.var << "size = static_cast<ub2> (size);";
}
@@ -515,14 +366,16 @@ namespace relational
traverse_float (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "indicator = is_null ? -1 : 0;";
}
virtual void
traverse_double (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "indicator = is_null ? -1 : 0;";
}
virtual void
@@ -535,6 +388,7 @@ namespace relational
<< "size," << endl
<< "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "indicator = is_null ? -1 : 0;"
<< "i." << mi.var << "size = static_cast<ub2> (size);";
}
@@ -542,28 +396,32 @@ namespace relational
traverse_date (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "indicator = is_null ? -1 : 0;";
}
virtual void
traverse_timestamp (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "indicator = is_null ? -1 : 0;";
}
virtual void
traverse_interval_ym (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "indicator = is_null ? -1 : 0;";
}
virtual void
traverse_interval_ds (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "indicator = is_null ? -1 : 0;";
}
virtual void
@@ -576,6 +434,7 @@ namespace relational
<< "size," << endl
<< "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "indicator = is_null ? -1 : 0;"
<< "i." << mi.var << "size = static_cast<ub2> (size);";
}
@@ -587,16 +446,9 @@ namespace relational
<< "i." << mi.var << "callback.callback.param," << endl
<< "i." << mi.var << "callback.context.param," << endl
<< "is_null," << endl
- << member << ");";
+ << member << ");"
+ << "i." << mi.var << "indicator = is_null ? -1 : 0;";
}
-
- private:
- string type;
- string db_type_id;
- string member;
- string traits;
-
- member_database_type_id member_database_type_id_;
};
entry<init_image_member> init_image_member_;
@@ -604,147 +456,21 @@ namespace relational
// init value
//
- struct init_value_member: relational::init_value_member, member_base
+ struct init_value_member: relational::init_value_member_impl<sql_type>,
+ member_base
{
init_value_member (base const& x)
- : member_base::base (x), // virtual base
- base (x),
- member_base (x),
- member_database_type_id_ (base::type_override_,
- base::fq_type_override_,
- base::key_prefix_)
- {
- }
-
- virtual bool
- pre (member_info& mi)
- {
- if (container (mi))
- return false;
-
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- string const& name (mi.m.name ());
- member = "o." + name;
-
- if (mi.cq)
- member = "const_cast< " + mi.fq_type (false) + "& > (" +
- member + ")";
-
- os << "// " << name << endl
- << "//" << endl;
- }
-
- // If this is a wrapped composite value, then we need to
- // "unwrap" it. For simple values this is taken care of
- // by the value_traits specializations.
- //
- if (mi.wrapper != 0 && composite (mi.t))
- {
- // Here we need the wrapper type, not the wrapped type.
- //
- member = "wrapper_traits< " + mi.fq_type (false) + " >::" +
- "set_ref (\n" + member + ")";
- }
-
- if (composite (mi.t))
- traits = "composite_value_traits< " + mi.fq_type () + " >";
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (mt))
- {
- type = "obj_traits::id_type";
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- // Handle NULL pointers and extract the id.
- //
- os << "{"
- << "typedef object_traits< " << class_fq_name (*c) <<
- " > obj_traits;"
- << "typedef pointer_traits< " << mi.fq_type () <<
- " > ptr_traits;"
- << endl
- << "if (i." << mi.var << "indicator == -1)" << endl;
-
- if (null (mi.m, key_prefix_))
- os << member << " = ptr_traits::pointer_type ();";
- else
- os << "throw null_pointer ();";
-
- os << "else"
- << "{"
- << type << " id;";
-
- member = "id";
- }
- else
- {
- type = mi.fq_type ();
- db_type_id = member_database_type_id_.database_type_id (mi.m);
- }
-
- traits = "oracle::value_traits<\n "
- + type + ",\n "
- + db_type_id + " >";
- }
-
- return true;
- }
-
- virtual void
- post (member_info& mi)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
{
- if (composite (mi.t))
- return;
-
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (object_pointer (mt))
- {
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- member = "o." + mi.m.name ();
-
- if (mi.cq)
- member = "const_cast< " + mi.fq_type (false) + "& > (" +
- member + ")";
- }
-
- if (lazy_pointer (mt))
- os << member << " = ptr_traits::pointer_type (db, 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
- << "db.load< obj_traits::object_type > (id));";
-
- os << "}"
- << "}";
- }
}
virtual void
- traverse_composite (member_info& mi)
+ get_null (member_info& mi)
{
- os << traits << "::init (" << endl
- << member << "," << endl
- << "i." << mi.var << "value," << endl
- << "db);"
- << endl;
+ os << "i." << mi.var << "indicator == -1";
}
virtual void
@@ -870,14 +596,6 @@ namespace relational
<< "i." << mi.var << "indicator == -1);"
<< endl;
}
-
- private:
- string type;
- string db_type_id;
- string traits;
- string member;
-
- member_database_type_id member_database_type_id_;
};
entry<init_value_member> init_value_member_;
diff --git a/odb/relational/pgsql/common.cxx b/odb/relational/pgsql/common.cxx
index 0ec9f7c..3d7e01e 100644
--- a/odb/relational/pgsql/common.cxx
+++ b/odb/relational/pgsql/common.cxx
@@ -16,91 +16,10 @@ namespace relational
// member_base
//
- void member_base::
- traverse (semantics::data_member& m)
+ sql_type const& member_base::
+ member_sql_type (semantics::data_member& m)
{
- if (transient (m))
- return;
-
- string var;
-
- if (!var_override_.empty ())
- var = var_override_;
- else
- {
- string const& name (m.name ());
- var = name + (name[name.size () - 1] == '_' ? "" : "_");
- }
-
- bool cq (type_override_ != 0 ? false : const_type (m.type ()));
- semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m));
-
- semantics::type* cont;
- if (semantics::class_* c = composite_wrapper (t))
- {
- // If t is a wrapper, pass the wrapped type. Also pass the
- // original, wrapper type.
- //
- member_info mi (m,
- *c,
- (wrapper (t) ? &t : 0),
- cq,
- var,
- fq_type_override_);
- if (pre (mi))
- {
- traverse_composite (mi);
- post (mi);
- }
- }
- // This cannot be a container if we have a type override.
- //
- else if (type_override_ == 0 && (cont = context::container (m)))
- {
- // The same unwrapping logic as for composite values.
- //
- member_info mi (m,
- *cont,
- (wrapper (t) ? &t : 0),
- cq,
- var,
- fq_type_override_);
- if (pre (mi))
- {
- traverse_container (mi);
- post (mi);
- }
- }
- else
- {
- sql_type const& st (column_sql_type (m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (t))
- {
- member_info mi (m,
- utype (*id_member (*c)),
- 0,
- cq,
- var,
- fq_type_override_);
- mi.st = &st;
- if (pre (mi))
- {
- traverse_object_pointer (mi);
- post (mi);
- }
- }
- else
- {
- member_info mi (m, t, 0, cq, var, fq_type_override_);
- mi.st = &st;
- if (pre (mi))
- {
- traverse_simple (mi);
- post (mi);
- }
- }
- }
+ return parse_sql_type (column_type (m, key_prefix_), m);
}
void member_base::
@@ -310,13 +229,21 @@ namespace relational
"id_string", // TEXT,
"id_bytea" // BYTEA
};
- }
+ }
+
+ member_database_type_id::
+ member_database_type_id (base const& x)
+ : member_base::base (x), // virtual base
+ base (x)
+ {
+ }
member_database_type_id::
member_database_type_id (semantics::type* type,
string const& fq_type,
string const& key_prefix)
- : relational::member_base (type, fq_type, key_prefix)
+ : member_base::base (type, fq_type, key_prefix), // virtual base
+ base (type, fq_type, key_prefix)
{
}
@@ -386,6 +313,8 @@ namespace relational
type_id_ = "pgsql::id_uuid";
}
+ entry<member_database_type_id> member_database_type_id_;
+
//
// query_columns
//
diff --git a/odb/relational/pgsql/common.hxx b/odb/relational/pgsql/common.hxx
index 4f3ee4d..4b9bbd5 100644
--- a/odb/relational/pgsql/common.hxx
+++ b/odb/relational/pgsql/common.hxx
@@ -12,118 +12,18 @@ namespace relational
{
namespace pgsql
{
- struct member_base: virtual relational::member_base, context
+ struct member_base: virtual relational::member_base_impl<sql_type>, context
{
- member_base (base const& x): base (x) {}
+ member_base (base const& x): base (x), base_impl (x) {}
// This c-tor is for the direct use inside the pgsql namespace.
// If you do use this c-tor, you should also explicitly call
- // relational::member_base.
+ // relational::member_base (aka base).
//
member_base () {}
- virtual void
- traverse (semantics::data_member& m);
-
- struct member_info
- {
- semantics::data_member& m; // Member.
- semantics::type& t; // Cvr-unqualified member C++ type, note
- // that m.type () may not be the same as t.
- semantics::type* wrapper; // Wrapper type if member is a composite or
- // container wrapper, also cvr-unqualified.
- // In this case t is the wrapped type.
- bool cq; // True if the original (wrapper) type
- // is const-qualified.
- sql_type const* st; // Member SQL type (only simple values).
- string& var; // Member variable name with trailing '_'.
-
- // C++ type fq-name.
- //
- string
- fq_type (bool unwrap = true) const
- {
- semantics::names* hint;
-
- if (wrapper != 0 && unwrap)
- {
- // Use the hint from the wrapper unless the wrapped type
- // is qualified.
- //
- hint = wrapper->get<semantics::names*> ("wrapper-hint");
- utype (*context::wrapper (*wrapper), hint);
- return t.fq_name (hint);
- }
-
- // Use the original type from 'm' instead of 't' since the hint
- // may be invalid for a different type. Plus, if a type is
- // overriden, then the fq_type must be as well.
- //
- if (fq_type_.empty ())
- {
- semantics::type& t (utype (m, hint));
- return t.fq_name (hint);
- }
- else
- return fq_type_;
- }
-
- string const& fq_type_;
-
- member_info (semantics::data_member& m_,
- semantics::type& t_,
- semantics::type* wrapper_,
- bool cq_,
- string& var_,
- string const& fq_type)
- : m (m_),
- t (t_),
- wrapper (wrapper_),
- cq (cq_),
- st (0),
- var (var_),
- fq_type_ (fq_type)
- {
- }
- };
-
- bool
- container (member_info& mi)
- {
- // This cannot be a container if we have a type override.
- //
- return type_override_ == 0 && context::container (mi.m);
- }
-
- // The false return value indicates that no further callbacks
- // should be called for this member.
- //
- virtual bool
- pre (member_info&)
- {
- return true;
- }
-
- virtual void
- post (member_info&)
- {
- }
-
- virtual void
- traverse_composite (member_info&)
- {
- }
-
- virtual void
- traverse_container (member_info&)
- {
- }
-
- virtual void
- traverse_object_pointer (member_info& mi)
- {
- traverse_simple (mi);
- }
+ virtual sql_type const&
+ member_sql_type (semantics::data_member&);
virtual void
traverse_simple (member_info&);
@@ -208,12 +108,16 @@ namespace relational
string type_;
};
- struct member_database_type_id: member_base
+ struct member_database_type_id: relational::member_database_type_id,
+ member_base
{
+ member_database_type_id (base const&);
+
member_database_type_id (semantics::type* type = 0,
string const& fq_type = string (),
string const& key_prefix = string ());
- string
+
+ virtual string
database_type_id (type&);
virtual void
diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx
index 8cc4eca..17ceaaa 100644
--- a/odb/relational/pgsql/context.cxx
+++ b/odb/relational/pgsql/context.cxx
@@ -236,17 +236,20 @@ namespace relational
//
sql_type const& context::
- column_sql_type (semantics::data_member& m, string const& kp)
+ parse_sql_type (string const& t, semantics::data_member& m)
{
- string key (kp.empty ()
- ? string ("pgsql-column-sql-type")
- : "pgsql-" + kp + "-column-sql-type");
+ // If this proves to be too expensive, we can maintain a
+ // cache of parsed types.
+ //
+ data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t));
- if (!m.count (key))
+ if (i != data_->sql_type_cache_.end ())
+ return i->second;
+ else
{
try
{
- m.set (key, parse_sql_type (column_type (m, kp)));
+ return (data_->sql_type_cache_[t] = parse_sql_type (t));
}
catch (invalid_sql_type const& e)
{
@@ -256,8 +259,6 @@ namespace relational
throw operation_failed ();
}
}
-
- return m.get<sql_type> (key);
}
sql_type context::
diff --git a/odb/relational/pgsql/context.hxx b/odb/relational/pgsql/context.hxx
index a79cceb..1da353a 100644
--- a/odb/relational/pgsql/context.hxx
+++ b/odb/relational/pgsql/context.hxx
@@ -5,6 +5,8 @@
#ifndef ODB_RELATIONAL_PGSQL_CONTEXT_HXX
#define ODB_RELATIONAL_PGSQL_CONTEXT_HXX
+#include <map>
+
#include <odb/relational/context.hxx>
namespace relational
@@ -69,8 +71,7 @@ namespace relational
{
public:
sql_type const&
- column_sql_type (semantics::data_member&,
- string const& key_prefix = string ());
+ parse_sql_type (string const&, semantics::data_member&);
public:
struct invalid_sql_type
@@ -124,6 +125,9 @@ namespace relational
struct data: base_context::data
{
data (std::ostream& os): base_context::data (os) {}
+
+ typedef std::map<string, sql_type> sql_type_cache;
+ sql_type_cache sql_type_cache_;
};
data* data_;
};
diff --git a/odb/relational/pgsql/model.cxx b/odb/relational/pgsql/model.cxx
index ebd04af..06a7dde 100644
--- a/odb/relational/pgsql/model.cxx
+++ b/odb/relational/pgsql/model.cxx
@@ -34,7 +34,7 @@ namespace relational
{
// Make sure the column is mapped to an integer type.
//
- switch (column_sql_type (m).type)
+ switch (parse_sql_type (column_type (), m).type)
{
case sql_type::SMALLINT:
case sql_type::INTEGER:
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
index ceb7dbd..ae19e05 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/relational/pgsql/source.cxx
@@ -103,7 +103,21 @@ namespace relational
struct statement_oids: object_columns_base, context
{
- statement_oids (statement_kind sk): sk_ (sk) {}
+ statement_oids (statement_kind sk, bool first = true)
+ : object_columns_base (first), sk_ (sk)
+ {
+ }
+
+ virtual void
+ traverse_pointer (semantics::data_member& m, semantics::class_& c)
+ {
+ // Ignore certain columns depending on what kind statement we are
+ // generating. See object_columns in common source generator for
+ // details.
+ //
+ if (!(inverse (m, key_prefix_) && sk_ != statement_select))
+ object_columns_base::traverse_pointer (m, c);
+ }
virtual bool
traverse_column (semantics::data_member& m,
@@ -114,10 +128,7 @@ namespace relational
// generating. See object_columns in common source generator for
// details.
//
- if (inverse (m) && sk_ != statement_select)
- return false;
-
- if ((id (m) || readonly (member_path_, member_scope_)) &&
+ if ((id () || readonly (member_path_, member_scope_)) &&
sk_ == statement_update)
return false;
@@ -128,7 +139,7 @@ namespace relational
if (!first)
os << ',' << endl;
- os << oids[column_sql_type (m).type];
+ os << oids[parse_sql_type (column_type (), m).type];
return true;
}
@@ -471,188 +482,37 @@ namespace relational
// init image
//
- struct init_image_member: relational::init_image_member, member_base
+ struct init_image_member: relational::init_image_member_impl<sql_type>,
+ member_base
{
init_image_member (base const& x)
- : member_base::base (x), // virtual base
- base (x),
- member_base (x),
- member_database_type_id_ (base::type_override_,
- base::fq_type_override_,
- base::key_prefix_)
- {
- }
-
- 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 (!member_override_.empty ())
- member = member_override_;
- else
- {
- // If we are generating standard init() and this member
- // contains version, ignore it.
- //
- if (version (mi.m))
- return false;
-
- string const& name (mi.m.name ());
- member = "o." + name;
-
- os << "// " << name << endl
- << "//" << endl;
-
- // If the whole class is readonly, then we will never be
- // called with sk == statement_update.
- //
- if (!readonly (*context::top_object))
- {
- semantics::class_* c;
-
- if (id (mi.m) ||
- readonly (mi.m) ||
- ((c = composite (mi.t)) && readonly (*c)))
- os << "if (sk == statement_insert)";
- }
- }
-
- // If this is a wrapped composite value, then we need to
- // "unwrap" it. For simple values this is taken care of
- // by the value_traits specializations.
- //
- if (mi.wrapper != 0 && composite (mi.t))
- {
- // Here we need the wrapper type, not the wrapped type.
- //
- member = "wrapper_traits< " + mi.fq_type (false) + " >::" +
- "get_ref (" + member + ")";
- }
-
- if (composite (mi.t))
- {
- os << "{";
- traits = "composite_value_traits< " + mi.fq_type () + " >";
- }
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (mt))
- {
- type = "obj_traits::id_type";
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- // Handle NULL pointers and extract the id.
- //
- os << "{"
- << "typedef object_traits< " << class_fq_name (*c) <<
- " > obj_traits;";
-
- if (weak_pointer (mt))
- {
- os << "typedef pointer_traits< " << mi.fq_type () <<
- " > wptr_traits;"
- << "typedef 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 pointer_traits< " << mi.fq_type () <<
- " > ptr_traits;"
- << endl;
-
- os << "bool is_null (ptr_traits::null_ptr (" << member << "));"
- << "if (!is_null)"
- << "{"
- << "const " << type << "& id (" << endl;
-
- if (lazy_pointer (mt))
- os << "ptr_traits::object_id< ptr_traits::element_type > (" <<
- member << ")";
- else
- os << "obj_traits::id (ptr_traits::get_ref (" << member << "))";
-
- os << ");"
- << endl;
-
- member = "id";
- }
- else
- {
- type = mi.fq_type ();
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- os << "{"
- << "bool is_null;";
- }
-
- traits = "pgsql::value_traits<\n "
- + type + ",\n "
- + db_type_id + " >";
- }
-
- return true;
- }
-
- virtual void
- post (member_info& mi)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
{
- if (composite (mi.t))
- os << "}";
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- if (object_pointer (member_utype (mi.m, key_prefix_)))
- {
- os << "}";
-
- if (!null (mi.m, key_prefix_))
- os << "else" << endl
- << "throw null_pointer ();";
- }
-
- os << "i." << mi.var << "null = is_null;"
- << "}";
- }
}
virtual void
- traverse_composite (member_info& mi)
+ set_null (member_info& mi)
{
- os << "if (" << traits << "::init (" << endl
- << "i." << mi.var << "value," << endl
- << member << "," << endl
- << "sk))" << endl
- << "grew = true;";
+ os << "i." << mi.var << "null = true;";
}
virtual void
traverse_integer (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "null = is_null;";
}
virtual void
traverse_float (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "null = is_null;";
}
virtual void
@@ -667,6 +527,7 @@ namespace relational
<< "size," << endl
<< "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "i." << mi.var << "size = size;"
<< "grew = grew || (cap != i." << mi.var << "value.capacity ());";
}
@@ -675,7 +536,8 @@ namespace relational
traverse_date_time (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "null = is_null;";
}
virtual void
@@ -688,6 +550,7 @@ namespace relational
<< "size," << endl
<< "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "i." << mi.var << "size = size;"
<< "grew = grew || (cap != i." << mi.var << "value.capacity ());";
}
@@ -702,6 +565,7 @@ namespace relational
<< "size," << endl
<< "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "i." << mi.var << "size = size;";
}
@@ -715,6 +579,7 @@ namespace relational
<< "size," << endl
<< "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "i." << mi.var << "size = size;"
<< "grew = grew || (cap != i." << mi.var << "value.capacity ());";
}
@@ -723,16 +588,9 @@ namespace relational
traverse_uuid (member_info& mi)
{
os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "null = is_null;";
}
-
- private:
- string type;
- string db_type_id;
- string member;
- string traits;
-
- member_database_type_id member_database_type_id_;
};
entry<init_image_member> init_image_member_;
@@ -740,147 +598,21 @@ namespace relational
// init value
//
- struct init_value_member: relational::init_value_member, member_base
+ struct init_value_member: relational::init_value_member_impl<sql_type>,
+ member_base
{
init_value_member (base const& x)
- : member_base::base (x), // virtual base
- base (x),
- member_base (x),
- member_database_type_id_ (base::type_override_,
- base::fq_type_override_,
- base::key_prefix_)
- {
- }
-
- virtual bool
- pre (member_info& mi)
- {
- if (container (mi))
- return false;
-
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- string const& name (mi.m.name ());
- member = "o." + name;
-
- if (mi.cq)
- member = "const_cast< " + mi.fq_type (false) + "& > (" +
- member + ")";
-
- os << "// " << name << endl
- << "//" << endl;
- }
-
- // If this is a wrapped composite value, then we need to
- // "unwrap" it. For simple values this is taken care of
- // by the value_traits specializations.
- //
- if (mi.wrapper != 0 && composite (mi.t))
- {
- // Here we need the wrapper type, not the wrapped type.
- //
- member = "wrapper_traits< " + mi.fq_type (false) + " >::" +
- "set_ref (\n" + member + ")";
- }
-
- if (composite (mi.t))
- traits = "composite_value_traits< " + mi.fq_type () + " >";
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (mt))
- {
- type = "obj_traits::id_type";
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- // Handle NULL pointers and extract the id.
- //
- os << "{"
- << "typedef object_traits< " << class_fq_name (*c) <<
- " > obj_traits;"
- << "typedef pointer_traits< " << mi.fq_type () <<
- " > ptr_traits;"
- << endl
- << "if (i." << mi.var << "null)" << endl;
-
- if (null (mi.m, key_prefix_))
- os << member << " = ptr_traits::pointer_type ();";
- else
- os << "throw null_pointer ();";
-
- os << "else"
- << "{"
- << type << " id;";
-
- member = "id";
- }
- else
- {
- type = mi.fq_type ();
- db_type_id = member_database_type_id_.database_type_id (mi.m);
- }
-
- traits = "pgsql::value_traits<\n "
- + type + ",\n "
- + db_type_id + " >";
- }
-
- return true;
- }
-
- virtual void
- post (member_info& mi)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
{
- if (composite (mi.t))
- return;
-
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (object_pointer (mt))
- {
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- member = "o." + mi.m.name ();
-
- if (mi.cq)
- member = "const_cast< " + mi.fq_type (false) + "& > (" +
- member + ")";
- }
-
- if (lazy_pointer (mt))
- os << member << " = ptr_traits::pointer_type (db, 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
- << "db.load< obj_traits::object_type > (id));";
-
- os << "}"
- << "}";
- }
}
virtual void
- traverse_composite (member_info& mi)
+ get_null (member_info& mi)
{
- os << traits << "::init (" << endl
- << member << "," << endl
- << "i." << mi.var << "value," << endl
- << "db);"
- << endl;
+ os << "i." << mi.var << "null";
}
virtual void
@@ -970,14 +702,6 @@ namespace relational
<< "i." << mi.var << "null);"
<< endl;
}
-
- private:
- string type;
- string db_type_id;
- string traits;
- string member;
-
- member_database_type_id member_database_type_id_;
};
entry<init_value_member> init_value_member_;
@@ -1090,7 +814,7 @@ namespace relational
<< "{";
instance<statement_oids> st (statement_select);
- st->traverse_column (*id, "", true);
+ st->traverse (*id);
os << "};";
}
@@ -1111,16 +835,11 @@ namespace relational
bool first (cc.total == cc.id + cc.inverse + cc.readonly +
cc.optimistic_managed);
- {
- instance<statement_oids> st (statement_where);
- st->traverse_column (*id, "", first);
- }
+ instance<statement_oids> st (statement_where, first);
+ st->traverse (*id);
if (optimistic != 0)
- {
- instance<statement_oids> st (statement_where);
- st->traverse_column (*optimistic, "", false);
- }
+ st->traverse (*optimistic);
os << "};";
}
@@ -1134,7 +853,7 @@ namespace relational
<< "{";
instance<statement_oids> st (statement_where);
- st->traverse_column (*id, "", true);
+ st->traverse (*id);
os << "};";
}
@@ -1145,15 +864,9 @@ namespace relational
<< "optimistic_erase_statement_types[] ="
<< "{";
- {
- instance<statement_oids> st (statement_where);
- st->traverse_column (*id, "", true);
- }
-
- {
- instance<statement_oids> st (statement_where);
- st->traverse_column (*optimistic, "", false);
- }
+ instance<statement_oids> st (statement_where);
+ st->traverse (*id);
+ st->traverse (*optimistic);
os << "};";
}
@@ -1258,8 +971,7 @@ namespace relational
bool inv (inv_m != 0);
semantics::type& vt (container_vt (t));
-
- string id_oid (oids[column_sql_type (m, "id").type]);
+ semantics::type& idt (container_idt (m));
// select_all statement types.
//
@@ -1268,20 +980,22 @@ namespace relational
<< "select_all_types[] ="
<< "{";
+ instance<statement_oids> so (statement_where);
+
if (inv)
{
// many(i)-to-many
//
if (container (*inv_m))
- os << oids[column_sql_type (*inv_m, "value").type];
+ so->traverse (*inv_m, idt, "value", "value");
// many(i)-to-one
//
else
- os << oids[column_sql_type (*inv_m).type];
+ so->traverse (*inv_m);
}
else
- os << id_oid;
+ so->traverse (m, idt, "id", "object_id");
os << "};";
}
@@ -1295,30 +1009,22 @@ namespace relational
if (!inv)
{
- os << id_oid << ",";
+ instance<statement_oids> so (statement_insert);
+
+ so->traverse (m, idt, "id", "object_id");
switch (container_kind (t))
{
case ck_ordered:
{
if (!unordered (m))
- os << oids[column_sql_type (m, "index").type] << ",";
-
+ so->traverse (m, container_it (t), "index", "index");
break;
}
case ck_map:
case ck_multimap:
{
- if (semantics::class_* ktc =
- composite_wrapper (container_kt (t)))
- {
- instance<statement_oids> st (statement_insert);
- st->traverse (m, *ktc, "key", "key");
- os << ",";
- }
- else
- os << oids[column_sql_type (m, "key").type] << ",";
-
+ so->traverse (m, container_kt (t), "key", "key");
break;
}
case ck_set:
@@ -1328,14 +1034,7 @@ namespace relational
}
}
- if (semantics::class_* vtc = composite_wrapper (vt))
- {
- instance <statement_oids> st (statement_insert);
- st->traverse (m, *vtc, "value", "value");
- }
- else
- os << oids[column_sql_type (m, "value").type];
-
+ so->traverse (m, vt, "value", "value");
}
else
// MSVC does not allow zero length arrays or uninitialized
@@ -1354,7 +1053,10 @@ namespace relational
<< "{";
if (!inv)
- os << id_oid;
+ {
+ instance<statement_oids> so (statement_where);
+ so->traverse (m, idt, "id", "object_id");
+ }
else
os << "0";
diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx
index 8c18f02..0bede14 100644
--- a/odb/relational/processor.cxx
+++ b/odb/relational/processor.cxx
@@ -142,7 +142,7 @@ namespace relational
// const auto_ptr<T> - can modify by changing the pointed-to value
//
if (const_type (m.type ()) &&
- !(m.count ("id") || m.count ("version") || m.count ("inverse")))
+ !(id (m) || version (m) || m.count ("inverse")))
{
if (qwt == 0 || const_type (*qwt))
m.set ("readonly", true);
@@ -153,11 +153,19 @@ namespace relational
if (composite_wrapper (t))
return;
- string type, ref_type;
+ string type, id_type;
+
+ if (m.count ("id-type"))
+ id_type = m.get<string> ("id-type");
if (m.count ("type"))
+ {
type = m.get<string> ("type");
+ if (id_type.empty ())
+ id_type = type;
+ }
+
if (semantics::class_* c = process_object_pointer (m, t))
{
// This is an object pointer. The column type is the pointed-to
@@ -168,26 +176,55 @@ namespace relational
semantics::names* idhint;
semantics::type& idt (utype (id, idhint));
+ semantics::type* wt (0);
+ semantics::names* whint (0);
+ if (process_wrapper (idt))
+ {
+ whint = idt.get<semantics::names*> ("wrapper-hint");
+ wt = &utype (*idt.get<semantics::type*> ("wrapper-type"), whint);
+ }
+
+ // Nothing to do if this is a composite value type.
+ //
+ if (composite_wrapper (idt))
+ return;
+
+ if (type.empty () && id.count ("id-type"))
+ type = id.get<string> ("id-type");
+
if (type.empty () && id.count ("type"))
type = id.get<string> ("type");
+ // The rest should be identical to the code for the id_type in
+ // the else block.
+ //
if (type.empty () && idt.count ("id-type"))
type = idt.get<string> ("id-type");
+ if (type.empty () && wt != 0 && wt->count ("id-type"))
+ type = wt->get<string> ("id-type");
+
if (type.empty () && idt.count ("type"))
type = idt.get<string> ("type");
+ if (type.empty () && wt != 0 && wt->count ("type"))
+ type = wt->get<string> ("type");
+
if (type.empty ())
type = database_type (idt, idhint, true);
+
+ if (type.empty () && wt != 0)
+ type = database_type (*wt, whint, true);
+
+ id_type = type;
}
else
{
- if (type.empty () && m.count ("id") && t.count ("id-type"))
- type = t.get<string> ("id-type");
+ if (id_type.empty () && t.count ("id-type"))
+ id_type = t.get<string> ("id-type");
- if (type.empty () && wt != 0 && m.count ("id") &&
- wt->count ("id-type"))
- type = wt->get<string> ("id-type");
+ if (id_type.empty () && wt != 0 && wt->count ("id-type"))
+ id_type = wt->get<string> ("id-type");
if (type.empty () && t.count ("type"))
type = t.get<string> ("type");
@@ -195,16 +232,29 @@ namespace relational
if (type.empty () && wt != 0 && wt->count ("type"))
type = wt->get<string> ("type");
+ if (id_type.empty ())
+ id_type = type;
+
+ if (id_type.empty ())
+ id_type = database_type (t, hint, true);
+
if (type.empty ())
- type = database_type (t, hint, m.count ("id"));
+ type = database_type (t, hint, false);
+
+ if (id_type.empty () && wt != 0)
+ id_type = database_type (*wt, whint, true);
if (type.empty () && wt != 0)
- type = database_type (*wt, whint, m.count ("id"));
+ type = database_type (*wt, whint, false);
+
+ if (id (m))
+ type = id_type;
}
if (!type.empty ())
{
m.set ("column-type", type);
+ m.set ("column-id-type", id_type);
// Issue a warning if we are relaxing null-ness.
//
@@ -274,24 +324,53 @@ namespace relational
if (obj_ptr && (c = process_object_pointer (m, t, prefix)))
{
// This is an object pointer. The column type is the pointed-to
- // object id type. Except by default it can be NULL.
+ // object id type.
//
semantics::data_member& id (*id_member (*c));
- semantics::names* hint;
- semantics::type& idt (utype (id, hint));
+ semantics::names* idhint;
+ semantics::type& idt (utype (id, idhint));
+
+ semantics::type* wt (0);
+ semantics::names* whint (0);
+ if (process_wrapper (idt))
+ {
+ whint = idt.get<semantics::names*> ("wrapper-hint");
+ wt = &utype (*idt.get<semantics::type*> ("wrapper-type"), whint);
+ }
+
+ // Nothing to do if this is a composite value type.
+ //
+ if (composite_wrapper (idt))
+ return;
+
+ if (type.empty () && id.count ("id-type"))
+ type = id.get<string> ("id-type");
if (type.empty () && id.count ("type"))
type = id.get<string> ("type");
+ // The rest of the code is identical to the else block except here
+ // we have to check for "id-type" before checking for "type".
+ //
+
if (type.empty () && idt.count ("id-type"))
type = idt.get<string> ("id-type");
+ if (type.empty () && wt != 0 && wt->count ("id-type"))
+ type = wt->get<string> ("id-type");
+
if (type.empty () && idt.count ("type"))
type = idt.get<string> ("type");
+ if (type.empty () && wt != 0 && wt->count ("type"))
+ type = wt->get<string> ("type");
+
if (type.empty ())
- type = database_type (idt, hint, true);
+ type = database_type (idt, idhint, true);
+
+ if (type.empty () && wt != 0)
+ type = database_type (*wt, whint, true);
}
else
{
@@ -311,6 +390,7 @@ namespace relational
if (!type.empty ())
{
m.set (prefix + "-column-type", type);
+ m.set (prefix + "-column-id-type", type);
return;
}
@@ -1094,7 +1174,7 @@ namespace relational
TREE_VEC_ELT (args, 0) = arg;
// This step should succeed regardles of whether there is a
- // container traits specialization for this type.
+ // specialization for this type.
//
tree inst (
lookup_template_class (t, args, 0, 0, 0, tf_warning_or_error));
@@ -1939,30 +2019,27 @@ namespace relational
}
virtual void
- traverse_simple (semantics::data_member& m)
+ traverse_pointer (semantics::data_member& m, semantics::class_& c)
{
- if (semantics::class_* c = object_pointer (utype (m)))
- {
- // Ignore inverse sides of the same relationship to avoid
- // phony conflicts caused by the direct side that will end
- // up in the relationship list as well.
- //
- if (inverse (m))
- return;
+ // Ignore inverse sides of the same relationship to avoid
+ // phony conflicts caused by the direct side that will end
+ // up in the relationship list as well.
+ //
+ if (inverse (m))
+ return;
- // Ignore self-pointers if requested.
- //
- if (!self_pointer_ && pointer_->obj == c)
- return;
+ // Ignore self-pointers if requested.
+ //
+ if (!self_pointer_ && pointer_->obj == &c)
+ return;
- if (pointee_.obj == c)
- {
- relationships_.push_back (relationship ());
- relationships_.back ().member = &m;
- relationships_.back ().name = member_prefix_ + m.name ();
- relationships_.back ().pointer = pointer_;
- relationships_.back ().pointee = &pointee_;
- }
+ if (pointee_.obj == &c)
+ {
+ relationships_.push_back (relationship ());
+ relationships_.back ().member = &m;
+ relationships_.back ().name = member_prefix_ + m.name ();
+ relationships_.back ().pointer = pointer_;
+ relationships_.back ().pointee = &pointee_;
}
}
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index 52ff093..7f94410 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -28,13 +28,15 @@ namespace relational
{
statement_column (): member (0) {}
statement_column (std::string const& c,
+ std::string const& t,
semantics::data_member& m,
std::string const& kp = "")
- : column (c), member (&m), key_prefix (kp)
+ : column (c), type (t), member (&m), key_prefix (kp)
{
}
- std::string column;
+ std::string column; // Column name.
+ std::string type; // Column SQL type.
semantics::data_member* member;
std::string key_prefix;
};
@@ -83,73 +85,108 @@ namespace relational
{
}
- virtual bool
- traverse_column (semantics::data_member& m, string const& name, bool)
+ virtual void
+ traverse_pointer (semantics::data_member& m, semantics::class_& c)
{
- semantics::data_member* im (inverse (m));
+ semantics::data_member* im (inverse (m, key_prefix_));
// Ignore certain columns depending on what kind statement we are
// generating. Columns corresponding to the inverse members are
- // only present in the select statements while the id and readonly
- // columns are not present in the update statements.
+ // only present in the select statements.
//
if (im != 0 && sk_ != statement_select)
- return false;
-
- if ((id (m) || readonly (member_path_, member_scope_)) &&
- sk_ == statement_update)
- return false;
+ return;
// Inverse object pointers come from a joined table.
//
if (im != 0)
{
- semantics::class_* c (object_pointer (utype (m)));
+ semantics::data_member& id (*id_member (c));
+ semantics::type& idt (utype (id));
if (container (*im))
{
// 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 (table_name_.empty () ? :) test may look wrong
- // at first but it is no.
+ // 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.
//
- column (
- *im,
- "id",
- table_name_.empty ()
- ? table_name_
- : table_qname (*im,
- table_prefix (schema (c->scope ()),
- table_name (*c) + "_",
- 1)),
- column_qname (*im, "id", "object_id"));
+ string table;
+
+ if (!table_name_.empty ())
+ {
+ table_prefix tp (schema (c.scope ()), table_name (c) + "_", 1);
+ table = table_qname (*im, tp);
+ }
+
+ instance<object_columns> oc (table, sk_, sc_);
+ oc->traverse (*im, idt, "id", "object_id", &c);
}
else
{
- semantics::data_member& id (*id_member (*c));
-
- // Use the join alias (column name) instead of the actual
- // table name unless we are handling a container. Note that
- // the (table_name_.empty () ? :) test may look wrong at
- // first but it is no.
+ // 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.
//
- column (
- id,
- "",
- table_name_.empty () ? table_name_ : quote_id (name),
- column_qname (id));
+ string table;
+
+ if (!table_name_.empty ())
+ {
+ if (composite_wrapper (idt))
+ {
+ string p (column_prefix (m, key_prefix_, default_name_));
+
+ if (p.empty ())
+ p = public_name_db (m);
+ else
+ p.resize (p.size () - 1); // Remove trailing underscore.
+
+ table = column_prefix_ + p;
+ }
+ else
+ table = column_prefix_ +
+ column_name (m, key_prefix_, default_name_);
+
+ table = quote_id (table);
+ }
+
+ instance<object_columns> oc (table, sk_, sc_);
+ oc->traverse (id);
}
}
else
- column (m, "", table_name_, quote_id (name));
+ 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)
+ return false;
+
+ column (m, table_name_, quote_id (name));
return true;
}
virtual void
column (semantics::data_member& m,
- string const& key_prefix,
string const& table,
string const& column)
{
@@ -177,7 +214,7 @@ namespace relational
r += param_->next ();
}
- sc_.push_back (statement_column (r, m, key_prefix));
+ sc_.push_back (statement_column (r, column_type (), m, key_prefix_));
}
protected:
@@ -350,7 +387,7 @@ namespace relational
virtual void
column (semantics::data_member& m, string const& column)
{
- sc_.push_back (statement_column (column, m));
+ sc_.push_back (statement_column (column, column_type (), m));
}
protected:
@@ -370,6 +407,7 @@ namespace relational
table_ (table_qname (scope)),
id_ (*id_member (scope))
{
+ id_cols_->traverse (id_);
}
size_t
@@ -399,31 +437,63 @@ namespace relational
}
}
- virtual bool
- traverse_column (semantics::data_member& m, string const& column, bool)
+ virtual void
+ traverse_pointer (semantics::data_member& m, semantics::class_& c)
{
- semantics::class_* c (object_pointer (utype (m)));
-
- if (c == 0)
- return false;
-
string t, a, dt, da;
std::ostringstream cond, dcond; // @@ diversion?
- if (semantics::data_member* im = inverse (m))
+ // 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;
+
+ if (composite_wrapper (utype (*id_member (c))))
+ {
+ string p (column_prefix (m, key_prefix_, default_name_));
+
+ if (p.empty ())
+ p = public_name_db (m);
+ else
+ p.resize (p.size () - 1); // Remove trailing underscore.
+
+ alias = column_prefix_ + p;
+ }
+ else
+ alias = column_prefix_ +
+ column_name (m, key_prefix_, default_name_);
+
+ if (semantics::data_member* im = inverse (m, key_prefix_))
{
if (container (*im))
{
// This container is a direct member of the class so the table
// prefix is just the class table name.
//
- qname const& ct (table_name (*c));
- table_prefix tp (schema (c->scope ()), ct + "_", 1);
+ qname const& ct (table_name (c));
+ table_prefix tp (schema (c.scope ()), ct + "_", 1);
t = table_qname (*im, tp);
- string const& val (column_qname (*im, "value", "value"));
- cond << t << '.' << val << " = " <<
- table_ << "." << column_qname (id_);
+ // Container's value is our id.
+ //
+ instance<object_columns_list> id_cols;
+ id_cols->traverse (*im, 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.
@@ -431,21 +501,44 @@ namespace relational
if (query_)
{
dt = quote_id (ct);
- da = quote_id (column);
+ da = quote_id (alias);
+
+ semantics::data_member& id (*id_member (c));
+
+ instance<object_columns_list> oid_cols, cid_cols;
+ oid_cols->traverse (id);
+ cid_cols->traverse (*im, 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)
+ {
- string const& id (column_qname (*im, "id", "object_id"));
+ if (i != b)
+ dcond << " AND ";
- dcond << da << '.' << column_qname (*id_member (*c)) << " = " <<
- t << '.' << id;
+ dcond << da << '.' << quote_id (j->name) << '=' <<
+ t << '.' << quote_id (i->name);
+ }
}
}
else
{
- t = table_qname (*c);
- a = quote_id (column);
+ t = table_qname (c);
+ a = quote_id (alias);
+
+ instance<object_columns_list> id_cols;
+ id_cols->traverse (*im);
+
+ 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 << '.' << column_qname (*im) << " = " <<
- table_ << "." << column_qname (id_);
+ cond << a << '.' << quote_id (i->name) << '=' <<
+ table_ << '.' << quote_id (j->name);
+ }
}
}
else if (query_)
@@ -453,11 +546,25 @@ namespace relational
// We need the join to be able to use the referenced object
// in the WHERE clause.
//
- t = table_qname (*c);
- a = quote_id (column);
+ t = table_qname (c);
+ a = quote_id (alias);
- cond << a << '.' << column_qname (*id_member (*c)) << " = " <<
- table_ << "." << quote_id (column);
+ 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);
+ }
}
if (!t.empty ())
@@ -478,14 +585,13 @@ namespace relational
joins_.back ().alias = da;
joins_.back ().cond = dcond.str ();
}
-
- return true;
}
private:
bool query_;
string table_;
semantics::data_member& id_;
+ instance<object_columns_list> id_cols_;
struct join
{
@@ -690,6 +796,207 @@ namespace relational
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::fq_type_override_,
+ base::key_prefix_)
+ {
+ }
+
+ typedef typename member_base_impl<T>::member_info member_info;
+
+ virtual void
+ set_null (member_info&) = 0;
+
+ 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 (!member_override_.empty ())
+ member = member_override_;
+ 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 && id (mi.m) && auto_ (mi.m))
+ return false;
+
+ string const& name (mi.m.name ());
+ member = "o." + name;
+
+ os << "// " << name << endl
+ << "//" << endl;
+
+ // If the whole class is readonly, then we will never be
+ // called with sk == statement_update.
+ //
+ if (!readonly (*context::top_object))
+ {
+ semantics::class_* c;
+
+ if (id (mi.m) ||
+ readonly (mi.m) ||
+ ((c = composite (mi.t)) && readonly (*c))) // Can't be id.
+ os << "if (sk == statement_insert)";
+ }
+ }
+
+ bool comp (composite (mi.t));
+
+ // If this is a wrapped composite value, then we need to "unwrap"
+ // it. For simple values this is taken care of by the value_traits
+ // specializations.
+ //
+ if (mi.wrapper != 0 && comp)
+ {
+ // Here we need the wrapper type, not the wrapped type.
+ //
+ member = "wrapper_traits< " + mi.fq_type (false) + " >::" +
+ "get_ref (" + member + ")";
+ }
+
+ if (mi.ptr != 0)
+ {
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ semantics::type& pt (member_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 pointer_traits< " << mi.ptr_fq_type () <<
+ " > wptr_traits;"
+ << "typedef 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 pointer_traits< " << mi.ptr_fq_type () <<
+ " > ptr_traits;"
+ << endl;
+
+ os << "bool is_null (ptr_traits::null_ptr (" << member << "));"
+ << "if (!is_null)"
+ << "{"
+ << "const " << type << "& 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 = "id";
+ }
+ else if (comp)
+ {
+ type = mi.fq_type ();
+
+ os << "{";
+ }
+ else
+ {
+ type = mi.fq_type ();
+
+ os << "{"
+ << "bool is_null;";
+ }
+
+ if (comp)
+ traits = "composite_value_traits< " + type + " >";
+ else
+ {
+ db_type_id = member_database_type_id_->database_type_id (mi.m);
+ traits = string (db.string ()) + "::value_traits<\n "
+ + type + ",\n "
+ + db_type_id + " >";
+ }
+
+ return true;
+ }
+
+ virtual void
+ post (member_info& mi)
+ {
+ if (mi.ptr != 0)
+ {
+ os << "}"
+ << "else" << endl;
+
+ // @@ Composite value currently cannot be NULL.
+ //
+ if (!null (mi.m, key_prefix_) || composite (mi.t))
+ os << "throw null_pointer ();";
+ else
+ set_null (mi);
+ }
+
+ os << "}";
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ bool grow (generate_grow && context::grow (mi.m, mi.t, key_prefix_));
+
+ if (grow)
+ os << "if (";
+
+ os << traits << "::init (" << endl
+ << "i." << mi.var << "value," << endl
+ << member << "," << endl
+ << "sk)";
+
+ 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;
@@ -755,6 +1062,171 @@ namespace relational
string member_override_;
};
+ 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::fq_type_override_,
+ base::key_prefix_)
+ {
+ }
+
+ typedef typename member_base_impl<T>::member_info member_info;
+
+ virtual void
+ get_null (member_info&) = 0;
+
+ virtual bool
+ pre (member_info& mi)
+ {
+ if (container (mi))
+ return false;
+
+ if (!member_override_.empty ())
+ member = member_override_;
+ else
+ {
+ string const& name (mi.m.name ());
+ member = "o." + name;
+
+ if (mi.cq)
+ {
+ string t (mi.ptr == 0 ? mi.fq_type (false) : mi.ptr_fq_type ());
+ member = "const_cast< " + t + "& > (" + member + ")";
+ }
+
+ os << "// " << name << endl
+ << "//" << endl;
+ }
+
+ bool comp (composite (mi.t));
+
+ // If this is a wrapped composite value, then we need to
+ // "unwrap" it. For simple values this is taken care of
+ // by the value_traits specializations.
+ //
+ if (mi.wrapper != 0 && comp)
+ {
+ // Here we need the wrapper type, not the wrapped type.
+ //
+ member = "wrapper_traits< " + mi.fq_type (false) + " >::" +
+ "set_ref (\n" + member + ")";
+ }
+
+ 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 pointer_traits< " << mi.ptr_fq_type () <<
+ " > ptr_traits;"
+ << endl;
+
+ // @@ Composite value currently cannot be NULL.
+ //
+ if (!comp)
+ {
+ os << "if (";
+ get_null (mi);
+ os << ")" << endl;
+
+ if (!null (mi.m, key_prefix_) )
+ os << "throw null_pointer ();";
+ else
+ os << member << " = ptr_traits::pointer_type ();";
+
+ os << "else"
+ << "{";
+ }
+
+ os << type << " id;";
+
+ member = "id";
+ }
+ else
+ type = mi.fq_type ();
+
+ if (comp)
+ traits = "composite_value_traits< " + type + " >";
+ else
+ {
+ db_type_id = member_database_type_id_->database_type_id (mi.m);
+ traits = string (db.string ()) + "::value_traits<\n "
+ + type + ",\n "
+ + db_type_id + " >";
+ }
+
+ return true;
+ }
+
+ virtual void
+ post (member_info& mi)
+ {
+ if (mi.ptr != 0)
+ {
+ if (!member_override_.empty ())
+ member = member_override_;
+ else
+ {
+ member = "o." + mi.m.name ();
+
+ if (mi.cq)
+ member = "const_cast< " + mi.ptr_fq_type () +
+ "& > (" + member + ")";
+ }
+
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ semantics::type& pt (member_utype (mi.m, key_prefix_));
+
+ if (lazy_pointer (pt))
+ os << member << " = ptr_traits::pointer_type (*db, 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
+ << "db->load< obj_traits::object_type > (id));";
+
+ // @@ Composite value currently cannot be NULL.
+ //
+ if (!composite (mi.t))
+ os << "}";
+
+ os << "}";
+ }
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ os << traits << "::init (" << endl
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "db);"
+ << endl;
+ }
+
+ protected:
+ string type;
+ string db_type_id;
+ string traits;
+ string member;
+
+ instance<member_database_type_id> member_database_type_id_;
+ };
+
struct init_value_base: traversal::class_, virtual context
{
typedef init_value_base base;
@@ -930,7 +1402,10 @@ namespace relational
//
if (!abst)
{
+ semantics::type& idt (container_idt (m));
+
string table (table_qname (m, table_prefix_));
+ instance<object_columns_list> id_cols;
// select_all_statement
//
@@ -940,10 +1415,12 @@ namespace relational
if (inverse)
{
semantics::class_* c (object_pointer (vt));
+ semantics::data_member& inv_id (*id_member (*c));
- string inv_table; // Other table name.
- string inv_id; // Other id column.
- string inv_fid; // Other foreign id column (ref to us).
+ string inv_table; // Other table name.
+ 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 (*im))
@@ -956,23 +1433,42 @@ namespace relational
//
table_prefix tp (schema (c->scope ()), table_name (*c) + "_", 1);
inv_table = table_qname (*im, tp);
- inv_id = column_qname (*im, "id", "object_id");
- inv_fid = column_qname (*im, "value", "value");
- sc.push_back (statement_column (
- inv_table + "." + inv_id, *im, "id"));
+ inv_id_cols->traverse (*im, utype (inv_id), "id", "object_id", c);
+ inv_fid_cols->traverse (*im, 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_table + "." + quote_id (i->name),
+ i->type,
+ *i->member,
+ inv_id_cols->size () == 1 ? "id" : ""));
+ }
}
else
{
// many(i)-to-one
//
- semantics::data_member& id (*id_member (*c));
-
inv_table = table_qname (*c);
- inv_id = column_qname (id);
- inv_fid = column_qname (*im);
- sc.push_back (statement_column (inv_table + "." + inv_id, id));
+ inv_id_cols->traverse (inv_id);
+ inv_fid_cols->traverse (*im);
+
+ for (object_columns_list::iterator i (inv_id_cols->begin ());
+ i != inv_id_cols->end (); ++i)
+ {
+ sc.push_back (
+ statement_column (
+ inv_table + "." + quote_id (i->name),
+ i->type,
+ *i->member));
+ }
}
process_statement_columns (sc, statement_select);
@@ -987,12 +1483,20 @@ namespace relational
}
instance<query_parameters> qp;
- os << strlit (" FROM " + inv_table +
- " WHERE " + inv_table + "." + inv_fid + "=" +
- qp->next ());
+ os << strlit (" FROM " + inv_table);
+
+ for (object_columns_list::iterator b (inv_fid_cols->begin ()),
+ i (b); i != inv_fid_cols->end (); ++i)
+ {
+ os << endl
+ << strlit ((i == b ? " WHERE " : " AND ") + inv_table + "." +
+ quote_id (i->name) + "=" + qp->next ());
+ }
}
else
{
+ id_cols->traverse (m, idt, "id", "object_id");
+
statement_columns sc;
statement_kind sk (statement_select); // Imperfect forwarding.
instance<object_columns> t (table, sk, sc);
@@ -1002,22 +1506,13 @@ namespace relational
case ck_ordered:
{
if (ordered)
- {
- string const& col (column_qname (m, "index", "index"));
- t->column (m, "index", table, col);
- }
+ t->traverse (m, *it, "index", "index");
break;
}
case ck_map:
case ck_multimap:
{
- if (semantics::class_* ckt = composite_wrapper (*kt))
- t->traverse (m, *ckt, "key", "key");
- else
- {
- string const& col (column_qname (m, "key", "key"));
- t->column (m, "key", table, col);
- }
+ t->traverse (m, *kt, "key", "key");
break;
}
case ck_set:
@@ -1027,13 +1522,7 @@ namespace relational
}
}
- if (semantics::class_* cvt = composite_wrapper (vt))
- t->traverse (m, *cvt, "value", "value");
- else
- {
- string const& col (column_qname (m, "value", "value"));
- t->column (m, "value", table, col);
- }
+ t->traverse (m, vt, "value", "value");
process_statement_columns (sc, statement_select);
@@ -1047,18 +1536,22 @@ namespace relational
}
instance<query_parameters> qp;
- string const& id_col (column_qname (m, "id", "object_id"));
+ os << strlit (" FROM " + table);
- os << strlit (" FROM " + table +
- " WHERE " + table + "." + id_col + "=" +
- qp->next ());
+ for (object_columns_list::iterator b (id_cols->begin ()), i (b);
+ i != id_cols->end (); ++i)
+ {
+ os << endl
+ << strlit ((i == b ? " WHERE " : " AND ") + table + "." +
+ quote_id (i->name) + "=" + qp->next ());
+ }
if (ordered)
{
string const& col (column_qname (m, "index", "index"));
os << endl
- << strlit (" ORDER BY " + table + "." + col) << endl;
+ << strlit (" ORDER BY " + table + "." + col);
}
}
@@ -1076,29 +1569,23 @@ namespace relational
else
{
statement_columns sc;
- sc.push_back (
- statement_column (
- column_qname (m, "id", "object_id"), m, "id"));
-
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->column (
- m, "index", "", column_qname (m, "index", "index"));
+ t->traverse (m, *it, "index", "index");
break;
}
case ck_map:
case ck_multimap:
{
- if (semantics::class_* ckt = composite_wrapper (*kt))
- t->traverse (m, *ckt, "key", "key");
- else
- t->column (m, "key", "", column_qname (m, "key", "key"));
+ t->traverse (m, *kt, "key", "key");
break;
}
case ck_set:
@@ -1108,10 +1595,7 @@ namespace relational
}
}
- if (semantics::class_* cvt = composite_wrapper (vt))
- t->traverse (m, *cvt, "value", "value");
- else
- t->column (m, "value", "", column_qname (m, "value", "value"));
+ t->traverse (m, vt, "value", "value");
process_statement_columns (sc, statement_insert);
@@ -1151,9 +1635,17 @@ namespace relational
{
instance<query_parameters> qp;
- os << strlit ("DELETE FROM " + table) << endl
- << strlit (" WHERE " + column_qname (m, "id", "object_id") +
- "=" + qp->next ()) << ";"
+ os << strlit ("DELETE FROM " + table);
+
+ for (object_columns_list::iterator b (id_cols->begin ()), i (b);
+ i != id_cols->end (); ++i)
+ {
+ os << endl
+ << strlit ((i == b ? " WHERE " : " AND ") +
+ quote_id (i->name) + "=" + qp->next ());
+ }
+
+ os << ";"
<< endl;
}
}
@@ -1462,10 +1954,10 @@ namespace relational
{
if (ordered)
os << "init (index_type& j, value_type& v, " <<
- "const data_image_type& i, database& db)";
+ "const data_image_type& i, database* db)";
else
os << "init (value_type& v, const data_image_type& i, " <<
- "database& db)";
+ "database* db)";
os << "{"
<< "ODB_POTENTIALLY_UNUSED (db);"
@@ -1487,7 +1979,7 @@ namespace relational
case ck_multimap:
{
os << "init (key_type& k, value_type& v, " <<
- "const data_image_type& i, database& db)"
+ "const data_image_type& i, database* db)"
<< "{"
<< "ODB_POTENTIALLY_UNUSED (db);"
<< endl
@@ -1504,7 +1996,7 @@ namespace relational
case ck_multiset:
{
os << "init (value_type& v, const data_image_type& i, " <<
- "database& db)"
+ "database* db)"
<< "{"
<< "ODB_POTENTIALLY_UNUSED (db);"
<< endl;
@@ -1652,21 +2144,21 @@ namespace relational
case ck_ordered:
{
os << "init (" << (ordered ? "i, " : "") <<
- "v, di, sts.connection ().database ());"
+ "v, di, &sts.connection ().database ());"
<< endl;
break;
}
case ck_map:
case ck_multimap:
{
- os << "init (k, v, di, sts.connection ().database ());"
+ os << "init (k, v, di, &sts.connection ().database ());"
<< endl;
break;
}
case ck_set:
case ck_multiset:
{
- os << "init (v, di, sts.connection ().database ());"
+ os << "init (v, di, &sts.connection ().database ());"
<< endl;
break;
}
@@ -2130,26 +2622,30 @@ namespace relational
}
virtual void
- traverse_simple (semantics::data_member& m)
+ traverse_pointer (semantics::data_member& m, semantics::class_& c)
{
if (!inverse (m))
- {
- string p;
+ object_members_base::traverse_pointer (m, c);
+ }
- if (version (m))
- p = "1";
- else if (id (m) && auto_ (m))
- p = qp_.auto_id ();
- else
- p = qp_.next ();
+ virtual void
+ traverse_simple (semantics::data_member& m)
+ {
+ string p;
- if (!p.empty ())
- {
- if (count_++ != 0)
- params_ += ',';
+ if (version (m))
+ p = "1";
+ else if (context::id (m) && auto_ (m)) // Only simple id can be auto.
+ p = qp_.auto_id ();
+ else
+ p = qp_.next ();
- params_ += p;
- }
+ if (!p.empty ())
+ {
+ if (count_++ != 0)
+ params_ += ',';
+
+ params_ += p;
}
}
@@ -2434,6 +2930,9 @@ namespace relational
<< traits << "::" << endl
<< "id (const image_type& i)"
<< "{"
+ << db << "::database* db (0);"
+ << "ODB_POTENTIALLY_UNUSED (db);"
+ << endl
<< "id_type id;";
init_id_value_member_->traverse (*id);
os << "return id;"
@@ -2505,11 +3004,14 @@ namespace relational
<< "{"
<< "std::size_t n (0);";
+ if (composite_wrapper (utype (*id)))
+ os << db << "::statement_kind sk (" << db << "::statement_select);";
+
bind_id_member_->traverse (*id);
if (optimistic != 0)
{
- os << "n++;" //@@ composite id
+ os << "n += " << column_count (c).id << ";"
<< endl;
bind_version_member_->traverse (*optimistic);
@@ -2549,7 +3051,7 @@ namespace relational
// init (object, image)
//
os << "void " << traits << "::" << endl
- << "init (object_type& o, const image_type& i, database& db)"
+ << "init (object_type& o, const image_type& i, database* db)"
<< "{"
<< "ODB_POTENTIALLY_UNUSED (o);"
<< "ODB_POTENTIALLY_UNUSED (i);"
@@ -2571,8 +3073,10 @@ namespace relational
<< "{";
if (grow_id)
- os << "bool grew (false);"
- << endl;
+ os << "bool grew (false);";
+
+ if (composite_wrapper (utype (*id)))
+ os << db << "::statement_kind sk (" << db << "::statement_select);";
init_id_image_member_->traverse (*id);
@@ -2677,7 +3181,8 @@ namespace relational
if (id != 0)
{
- string const& id_col (column_qname (*id));
+ instance<object_columns_list> id_cols;
+ id_cols->traverse (*id);
// find_statement
//
@@ -2702,14 +3207,23 @@ namespace relational
os << strlit (" FROM " + table) << endl;
- bool f (false);
+ bool f (false); // @@ (im)perfect forwarding
instance<object_joins> j (c, f); // @@ (im)perfect forwarding
j->traverse (c);
j->write ();
instance<query_parameters> qp;
- os << strlit (" WHERE " + table + "." + id_col + "=" +
- qp->next ()) << ";"
+ for (object_columns_list::iterator b (id_cols->begin ()), i (b);
+ i != id_cols->end (); ++i)
+ {
+ if (i != b)
+ os << endl;
+
+ os << strlit ((i == b ? " WHERE " : " AND ") + table + "." +
+ quote_id (i->name) + "=" + qp->next ());
+ }
+
+ os << ";"
<< endl;
}
@@ -2739,13 +3253,22 @@ namespace relational
os << strlit (c + (++i != e ? "," : "")) << endl;
}
- string where (" WHERE " + id_col + "=" + qp->next ());
+ for (object_columns_list::iterator b (id_cols->begin ()), i (b);
+ i != id_cols->end (); ++i)
+ {
+ if (i != b)
+ os << endl;
+
+ os << strlit ((i == b ? " WHERE " : " AND ") +
+ quote_id (i->name) + "=" + qp->next ());
+ }
if (optimistic != 0)
- where += " AND " + column_qname (*optimistic) + "=" +
- qp->next ();
+ os << endl
+ << strlit (" AND " + column_qname (*optimistic) +
+ "=" + qp->next ());
- os << strlit (where) << ";"
+ os << ";"
<< endl;
}
@@ -2754,8 +3277,18 @@ namespace relational
{
instance<query_parameters> qp;
os << "const char " << traits << "::erase_statement[] =" << endl
- << strlit ("DELETE FROM " + table) << endl
- << strlit (" WHERE " + id_col + "=" + qp->next ()) << ";"
+ << strlit ("DELETE FROM " + table);
+
+ for (object_columns_list::iterator b (id_cols->begin ()), i (b);
+ i != id_cols->end (); ++i)
+ {
+
+ os << endl
+ << strlit ((i == b ? " WHERE " : " AND ") +
+ quote_id (i->name) + "=" + qp->next ());
+ }
+
+ os << ";"
<< endl;
}
@@ -2763,13 +3296,21 @@ namespace relational
{
instance<query_parameters> qp;
- string where (" WHERE " + id_col + "=" + qp->next ());
- where += " AND " + column_qname (*optimistic) + "=" + qp->next ();
-
os << "const char " << traits <<
"::optimistic_erase_statement[] =" << endl
- << strlit ("DELETE FROM " + table) << endl
- << strlit (where) << ";"
+ << strlit ("DELETE FROM " + table);
+
+ for (object_columns_list::iterator b (id_cols->begin ()), i (b);
+ i != id_cols->end (); ++i)
+ {
+ os << endl
+ << strlit ((i == b ? " WHERE " : " AND ") +
+ quote_id (i->name) + "=" + qp->next ());
+ }
+
+ os << endl
+ << strlit (" AND " + column_qname (*optimistic) +
+ "=" + qp->next ()) << ";"
<< endl;
}
}
@@ -2786,10 +3327,6 @@ namespace relational
process_statement_columns (sc, statement_select);
}
- bool t (true);
- instance<object_joins> oj (c, t); //@@ (im)perfect forwarding
- oj->traverse (c);
-
os << "const char " << traits << "::query_statement[] =" << endl
<< strlit ("SELECT ") << endl;
@@ -2801,7 +3338,15 @@ namespace relational
}
os << strlit (" FROM " + table) << endl;
- oj->write ();
+
+ if (id != 0)
+ {
+ bool t (true); //@@ (im)perfect forwarding
+ instance<object_joins> oj (c, t); //@@ (im)perfect forwarding
+ oj->traverse (c);
+ oj->write ();
+ }
+
os << strlit (" ") << ";"
<< endl;
@@ -3202,7 +3747,7 @@ namespace relational
<< "if (l.locked ())"
<< "{"
<< "callback (db, obj, callback_event::pre_load);"
- << "init (obj, sts.image (), db);";
+ << "init (obj, sts.image (), &db);";
init_value_extra ();
free_statement_result_delayed ();
@@ -3248,7 +3793,7 @@ namespace relational
<< "reference_cache_traits< object_type >::insert (db, id, obj));"
<< endl
<< "callback (db, obj, callback_event::pre_load);"
- << "init (obj, sts.image (), db);";
+ << "init (obj, sts.image (), &db);";
init_value_extra ();
free_statement_result_delayed ();
@@ -3298,7 +3843,7 @@ namespace relational
}
os << "callback (db, obj, callback_event::pre_load);"
- << "init (obj, sts.image (), db);";
+ << "init (obj, sts.image (), &db);";
init_value_extra ();
free_statement_result_delayed ();
@@ -3766,7 +4311,7 @@ namespace relational
// init (view, image)
//
os << "void " << traits << "::" << endl
- << "init (view_type& o, const image_type& i, database& db)"
+ << "init (view_type& o, const image_type& i, database* db)"
<< "{"
<< "ODB_POTENTIALLY_UNUSED (o);"
<< "ODB_POTENTIALLY_UNUSED (i);"
@@ -4080,7 +4625,7 @@ namespace relational
if (im != 0)
{
// For now a direct member can only be directly in
- // the object scope. When this changes, the inverse()
+ // the object scope. If this changes, the inverse()
// function would have to return a member path instead
// of just a single member.
//
@@ -4102,34 +4647,36 @@ namespace relational
// If we are the pointed-to object, then we have to turn
// things around. This is necessary to have the proper
- // JOIN order. There seems to be a pattern there but
- // it is not yet intuitively clear what it means.
+ // JOIN order. There seems to be a pattern there but it
+ // is not yet intuitively clear what it means.
//
+ instance<object_columns_list> c_cols; // Container columns.
+ instance<object_columns_list> o_cols; // Object columns.
+
+ qname* ot; // Object table (either lt or rt).
+
if (im != 0)
{
if (i->obj == c)
{
// container.value = pointer.id
//
- l = ct;
- l += '.';
- l += column_qname (*im, "value", "value");
- l += "=";
- l += quote_id (lt);
- l += '.';
- l += column_qname (*id_member (*e.vo->obj));
+ semantics::data_member& id (*id_member (*e.vo->obj));
+
+ c_cols->traverse (*im, utype (id), "value", "value");
+ o_cols->traverse (id);
+ ot = &lt;
}
else
{
// container.id = pointed-to.id
//
- l = ct;
- l += '.';
- l += column_qname (*im, "id", "object_id");
- l += "=";
- l += quote_id (rt);
- l += '.';
- l += column_qname (*id_member (*vo->obj));
+ semantics::data_member& id (*id_member (*vo->obj));
+
+ c_cols->traverse (
+ *im, utype (id), "id", "object_id", vo->obj);
+ o_cols->traverse (id);
+ ot = &rt;
}
}
else
@@ -4138,29 +4685,43 @@ namespace relational
{
// container.id = pointer.id
//
- l = ct;
- l += '.';
- l += column_qname (m, "id", "object_id");
- l += "=";
- l += quote_id (lt);
- l += '.';
- l += column_qname (*id_member (*e.vo->obj));
+ semantics::data_member& id (*id_member (*e.vo->obj));
+
+ c_cols->traverse (
+ m, utype (id), "id", "object_id", e.vo->obj);
+ o_cols->traverse (id);
+ ot = &lt;
}
else
{
// container.value = pointed-to.id
//
- l = ct;
- l += '.';
- l += column_qname (m, "value", "value");
- l += "=";
- l += quote_id (rt);
- l += '.';
- l += column_qname (*id_member (*vo->obj));
+ semantics::data_member& id (*id_member (*vo->obj));
+
+ c_cols->traverse (m, utype (id), "value", "value");
+ o_cols->traverse (id);
+ ot = &rt;
}
}
- os << "r += " << strlit (l) << ";";
+ for (object_columns_list::iterator b (c_cols->begin ()), i (b),
+ j (o_cols->begin ()); i != c_cols->end (); ++i, ++j)
+ {
+ l.clear ();
+
+ if (i != b)
+ l += "AND ";
+
+ l += ct;
+ l += '.';
+ l += quote_id (i->name);
+ l += '=';
+ l += quote_id (*ot);
+ l += '.';
+ l += quote_id (j->name);
+
+ os << "r += " << strlit (l) << ";";
+ }
}
l = "LEFT JOIN ";
@@ -4174,31 +4735,33 @@ namespace relational
if (cont != 0)
{
+ instance<object_columns_list> c_cols; // Container columns.
+ instance<object_columns_list> o_cols; // Object columns.
+
+ qname* ot; // Object table (either lt or rt).
+
if (im != 0)
{
if (i->obj == c)
{
// container.id = pointed-to.id
//
- l = ct;
- l += '.';
- l += column_qname (*im, "id", "object_id");
- l += "=";
- l += quote_id (rt);
- l += '.';
- l += column_qname (*id_member (*vo->obj));
+ semantics::data_member& id (*id_member (*vo->obj));
+
+ c_cols->traverse (
+ *im, utype (id), "id", "object_id", vo->obj);
+ o_cols->traverse (id);
+ ot = &rt;
}
else
{
// container.value = pointer.id
//
- l = ct;
- l += '.';
- l += column_qname (*im, "value", "value");
- l += "=";
- l += quote_id (lt);
- l += '.';
- l += column_qname (*id_member (*e.vo->obj));
+ semantics::data_member& id (*id_member (*e.vo->obj));
+
+ c_cols->traverse (*im, utype (id), "value", "value");
+ o_cols->traverse (id);
+ ot = &lt;
}
}
else
@@ -4207,58 +4770,91 @@ namespace relational
{
// container.value = pointed-to.id
//
- l = ct;
- l += '.';
- l += column_qname (m, "value", "value");
- l += "=";
- l += quote_id (rt);
- l += '.';
- l += column_qname (*id_member (*vo->obj));
+ semantics::data_member& id (*id_member (*vo->obj));
+
+ c_cols->traverse (m, utype (id), "value", "value");
+ o_cols->traverse (id);
+ ot = &rt;
}
else
{
// container.id = pointer.id
//
- l = ct;
- l += '.';
- l += column_qname (m, "id", "object_id");
- l += "=";
- l += quote_id (lt);
- l += '.';
- l += column_qname (*id_member (*e.vo->obj));
+ semantics::data_member& id (*id_member (*e.vo->obj));
+
+ c_cols->traverse (
+ m, utype (id), "id", "object_id", e.vo->obj);
+ o_cols->traverse (id);
+ ot = &lt;
}
}
+
+ for (object_columns_list::iterator b (c_cols->begin ()), i (b),
+ j (o_cols->begin ()); i != c_cols->end (); ++i, ++j)
+ {
+ l.clear ();
+
+ if (i != b)
+ l += "AND ";
+
+ l += ct;
+ l += '.';
+ l += quote_id (i->name);
+ l += '=';
+ l += quote_id (*ot);
+ l += '.';
+ l += quote_id (j->name);
+
+ os << "r += " << strlit (l) << ";";
+ }
}
else
{
+ string col_prefix;
+
+ if (im == 0)
+ col_prefix =
+ object_columns_base::column_prefix (e.member_path);
+
+ instance<object_columns_list> l_cols (col_prefix);
+ instance<object_columns_list> r_cols;
+
if (im != 0)
{
// our.id = pointed-to.pointer
//
- l = quote_id (lt);
- l += '.';
- l += column_qname (*id_member (*e.vo->obj));
- l += " = ";
- l += quote_id (rt);
- l += '.';
- l += column_qname (*im);
+ l_cols->traverse (*id_member (*e.vo->obj));
+ r_cols->traverse (*im);
}
else
{
// our.pointer = pointed-to.id
//
- l = quote_id (lt);
+ l_cols->traverse (*e.member_path.back ());
+ r_cols->traverse (*id_member (*vo->obj));
+ }
+
+ 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 += quote_id (lt);
l += '.';
- l += column_qname (e.member_path);
- l += " = ";
+ l += quote_id (i->name);
+ l += '=';
l += quote_id (rt);
l += '.';
- l += column_qname (*id_member (*vo->obj));
+ l += quote_id (j->name);
+
+ os << "r += " << strlit (l) << ";";
}
}
- os << "r += " << strlit (l) << ";"
- << endl;
+ os << endl;
}
// Generate the query condition.
@@ -4499,7 +5095,7 @@ namespace relational
// init (value, image)
//
os << "void " << traits << "::" << endl
- << "init (value_type& o, const image_type& i, database& db)"
+ << "init (value_type& o, const image_type& i, database* db)"
<< "{"
<< "ODB_POTENTIALLY_UNUSED (o);"
<< "ODB_POTENTIALLY_UNUSED (i);"
@@ -4588,8 +5184,12 @@ namespace relational
<< "#include <odb/" << db << "/connection.hxx>" << endl
<< "#include <odb/" << db << "/statement.hxx>" << endl
<< "#include <odb/" << db << "/statement-cache.hxx>" << endl
- << "#include <odb/" << db << "/object-statements.hxx>" << endl
- << "#include <odb/" << db << "/container-statements.hxx>" << endl
+ << "#include <odb/" << db << "/object-statements.hxx>" << endl;
+
+ if (options.generate_query ())
+ os << "#include <odb/" << db << "/view-statements.hxx>" << endl;
+
+ os << "#include <odb/" << db << "/container-statements.hxx>" << endl
<< "#include <odb/" << db << "/exceptions.hxx>" << endl;
if (options.generate_query ())
diff --git a/odb/relational/sqlite/common.cxx b/odb/relational/sqlite/common.cxx
index 480b69a..7164ef3 100644
--- a/odb/relational/sqlite/common.cxx
+++ b/odb/relational/sqlite/common.cxx
@@ -16,91 +16,10 @@ namespace relational
// member_base
//
- void member_base::
- traverse (semantics::data_member& m)
+ sql_type const& member_base::
+ member_sql_type (semantics::data_member& m)
{
- if (transient (m))
- return;
-
- string var;
-
- if (!var_override_.empty ())
- var = var_override_;
- else
- {
- string const& name (m.name ());
- var = name + (name[name.size () - 1] == '_' ? "" : "_");
- }
-
- bool cq (type_override_ != 0 ? false : const_type (m.type ()));
- semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m));
-
- semantics::type* cont;
- if (semantics::class_* c = composite_wrapper (t))
- {
- // If t is a wrapper, pass the wrapped type. Also pass the
- // original, wrapper type.
- //
- member_info mi (m,
- *c,
- (wrapper (t) ? &t : 0),
- cq,
- var,
- fq_type_override_);
- if (pre (mi))
- {
- traverse_composite (mi);
- post (mi);
- }
- }
- // This cannot be a container if we have a type override.
- //
- else if (type_override_ == 0 && (cont = context::container (m)))
- {
- // The same unwrapping logic as for composite values.
- //
- member_info mi (m,
- *cont,
- (wrapper (t) ? &t : 0),
- cq,
- var,
- fq_type_override_);
- if (pre (mi))
- {
- traverse_container (mi);
- post (mi);
- }
- }
- else
- {
- sql_type const& st (column_sql_type (m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (t))
- {
- member_info mi (m,
- utype (*id_member (*c)),
- 0,
- cq,
- var,
- fq_type_override_);
- mi.st = &st;
- if (pre (mi))
- {
- traverse_object_pointer (mi);
- post (mi);
- }
- }
- else
- {
- member_info mi (m, t, 0, cq, var, fq_type_override_);
- mi.st = &st;
- if (pre (mi))
- {
- traverse_simple (mi);
- post (mi);
- }
- }
- }
+ return parse_sql_type (column_type (m, key_prefix_), m);
}
void member_base::
@@ -185,10 +104,18 @@ namespace relational
//
member_database_type_id::
+ member_database_type_id (base const& x)
+ : member_base::base (x), // virtual base
+ base (x)
+ {
+ }
+
+ member_database_type_id::
member_database_type_id (semantics::type* type,
- string const& fq_type,
- string const& key_prefix)
- : relational::member_base (type, fq_type, key_prefix)
+ string const& fq_type,
+ string const& key_prefix)
+ : member_base::base (type, fq_type, key_prefix), // virtual base
+ base (type, fq_type, key_prefix)
{
}
@@ -230,6 +157,8 @@ namespace relational
type_id_ = "sqlite::id_blob";
}
+ entry<member_database_type_id> member_database_type_id_;
+
//
// query_columns
//
diff --git a/odb/relational/sqlite/common.hxx b/odb/relational/sqlite/common.hxx
index 7885a04..941e200 100644
--- a/odb/relational/sqlite/common.hxx
+++ b/odb/relational/sqlite/common.hxx
@@ -12,118 +12,18 @@ namespace relational
{
namespace sqlite
{
- struct member_base: virtual relational::member_base, context
+ struct member_base: virtual relational::member_base_impl<sql_type>, context
{
- member_base (base const& x): base (x) {}
+ member_base (base const& x): base (x), base_impl (x) {}
// This c-tor is for the direct use inside the sqlite namespace.
// If you do use this c-tor, you should also explicitly call
- // relational::member_base.
+ // relational::member_base (aka base).
//
member_base () {}
- virtual void
- traverse (semantics::data_member& m);
-
- struct member_info
- {
- semantics::data_member& m; // Member.
- semantics::type& t; // Cvr-unqualified member C++ type, note
- // that m.type () may not be the same as t.
- semantics::type* wrapper; // Wrapper type if member is a composite or
- // container wrapper, also cvr-unqualified.
- // In this case t is the wrapped type.
- bool cq; // True if the original (wrapper) type
- // is const-qualified.
- sql_type const* st; // Member SQL type (only simple values).
- string& var; // Member variable name with trailing '_'.
-
- // C++ type fq-name.
- //
- string
- fq_type (bool unwrap = true) const
- {
- semantics::names* hint;
-
- if (wrapper != 0 && unwrap)
- {
- // Use the hint from the wrapper unless the wrapped type
- // is qualified.
- //
- hint = wrapper->get<semantics::names*> ("wrapper-hint");
- utype (*context::wrapper (*wrapper), hint);
- return t.fq_name (hint);
- }
-
- // Use the original type from 'm' instead of 't' since the hint
- // may be invalid for a different type. Plus, if a type is
- // overriden, then the fq_type must be as well.
- //
- if (fq_type_.empty ())
- {
- semantics::type& t (utype (m, hint));
- return t.fq_name (hint);
- }
- else
- return fq_type_;
- }
-
- string const& fq_type_;
-
- member_info (semantics::data_member& m_,
- semantics::type& t_,
- semantics::type* wrapper_,
- bool cq_,
- string& var_,
- string const& fq_type)
- : m (m_),
- t (t_),
- wrapper (wrapper_),
- cq (cq_),
- st (0),
- var (var_),
- fq_type_ (fq_type)
- {
- }
- };
-
- bool
- container (member_info& mi)
- {
- // This cannot be a container if we have a type override.
- //
- return type_override_ == 0 && context::container (mi.m);
- }
-
- // The false return value indicates that no further callbacks
- // should be called for this member.
- //
- virtual bool
- pre (member_info&)
- {
- return true;
- }
-
- virtual void
- post (member_info&)
- {
- }
-
- virtual void
- traverse_composite (member_info&)
- {
- }
-
- virtual void
- traverse_container (member_info&)
- {
- }
-
- virtual void
- traverse_object_pointer (member_info& mi)
- {
- traverse_simple (mi);
- }
+ virtual sql_type const&
+ member_sql_type (semantics::data_member&);
virtual void
traverse_simple (member_info&);
@@ -182,12 +82,16 @@ namespace relational
string type_;
};
- struct member_database_type_id: member_base
+ struct member_database_type_id: relational::member_database_type_id,
+ member_base
{
+ member_database_type_id (base const&);
+
member_database_type_id (semantics::type* type = 0,
string const& fq_type = string (),
string const& key_prefix = string ());
- string
+
+ virtual string
database_type_id (type&);
virtual void
diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx
index b04dcb9..46689bd 100644
--- a/odb/relational/sqlite/context.cxx
+++ b/odb/relational/sqlite/context.cxx
@@ -365,17 +365,20 @@ namespace relational
}
sql_type const& context::
- column_sql_type (semantics::data_member& m, string const& kp)
+ parse_sql_type (string const& t, semantics::data_member& m)
{
- string key (kp.empty ()
- ? string ("sqlite-column-sql-type")
- : "sqlite-" + kp + "-column-sql-type");
+ // If this proves to be too expensive, we can maintain a
+ // cache of parsed types.
+ //
+ data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t));
- if (!m.count (key))
+ if (i != data_->sql_type_cache_.end ())
+ return i->second;
+ else
{
try
{
- m.set (key, parse_sql_type (column_type (m, kp)));
+ return (data_->sql_type_cache_[t] = parse_sql_type (t));
}
catch (invalid_sql_type const& e)
{
@@ -385,8 +388,6 @@ namespace relational
throw operation_failed ();
}
}
-
- return m.get<sql_type> (key);
}
sql_type context::
diff --git a/odb/relational/sqlite/context.hxx b/odb/relational/sqlite/context.hxx
index e9f755c..4123b0c 100644
--- a/odb/relational/sqlite/context.hxx
+++ b/odb/relational/sqlite/context.hxx
@@ -5,6 +5,8 @@
#ifndef ODB_RELATIONAL_SQLITE_CONTEXT_HXX
#define ODB_RELATIONAL_SQLITE_CONTEXT_HXX
+#include <map>
+
#include <odb/relational/context.hxx>
namespace relational
@@ -33,8 +35,7 @@ namespace relational
{
public:
sql_type const&
- column_sql_type (semantics::data_member&,
- string const& key_prefix = string ());
+ parse_sql_type (string const&, semantics::data_member&);
public:
struct invalid_sql_type
@@ -87,6 +88,9 @@ namespace relational
struct data: base_context::data
{
data (std::ostream& os): base_context::data (os) {}
+
+ typedef std::map<string, sql_type> sql_type_cache;
+ sql_type_cache sql_type_cache_;
};
data* data_;
diff --git a/odb/relational/sqlite/model.cxx b/odb/relational/sqlite/model.cxx
index 60522a3..41d5d6c 100644
--- a/odb/relational/sqlite/model.cxx
+++ b/odb/relational/sqlite/model.cxx
@@ -28,7 +28,7 @@ namespace relational
{
// Make sure the column is mapped to INTEGER.
//
- if (column_sql_type (m).type != sql_type::INTEGER)
+ if (parse_sql_type (column_type (), m).type != sql_type::INTEGER)
{
cerr << m.file () << ":" << m.line () << ":" << m.column ()
<< ": error: column with default value specified as C++ "
diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx
index 024694f..c170904 100644
--- a/odb/relational/sqlite/source.cxx
+++ b/odb/relational/sqlite/source.cxx
@@ -269,173 +269,21 @@ namespace relational
// init image
//
- struct init_image_member: relational::init_image_member, member_base
+ struct init_image_member: relational::init_image_member_impl<sql_type>,
+ member_base
{
init_image_member (base const& x)
- : member_base::base (x), // virtual base
- base (x),
- member_base (x),
- member_database_type_id_ (base::type_override_,
- base::fq_type_override_,
- base::key_prefix_)
- {
- }
-
- 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 (!member_override_.empty ())
- member = member_override_;
- else
- {
- // If we are generating standard init() and this member
- // contains version, ignore it.
- //
- if (version (mi.m))
- return false;
-
- string const& name (mi.m.name ());
- member = "o." + name;
-
- os << "// " << name << endl
- << "//" << endl;
-
- // If the whole class is readonly, then we will never be
- // called with sk == statement_update.
- //
- if (!readonly (*context::top_object))
- {
- semantics::class_* c;
-
- if (id (mi.m) ||
- readonly (mi.m) ||
- ((c = composite (mi.t)) && readonly (*c)))
- os << "if (sk == statement_insert)";
- }
- }
-
- // If this is a wrapped composite value, then we need to
- // "unwrap" it. For simple values this is taken care of
- // by the value_traits specializations.
- //
- if (mi.wrapper != 0 && composite (mi.t))
- {
- // Here we need the wrapper type, not the wrapped type.
- //
- member = "wrapper_traits< " + mi.fq_type (false) + " >::" +
- "get_ref (" + member + ")";
- }
-
- if (composite (mi.t))
- {
- os << "{";
- traits = "composite_value_traits< " + mi.fq_type () + " >";
- }
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (mt))
- {
- type = "obj_traits::id_type";
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- // Handle NULL pointers and extract the id.
- //
- os << "{"
- << "typedef object_traits< " << class_fq_name (*c) <<
- " > obj_traits;";
-
- if (weak_pointer (mt))
- {
- os << "typedef pointer_traits< " << mi.fq_type () <<
- " > wptr_traits;"
- << "typedef 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 pointer_traits< " << mi.fq_type () <<
- " > ptr_traits;"
- << endl;
-
- os << "i." << mi.var << "null = ptr_traits::null_ptr (" <<
- member << ");"
- << "if (!i." << mi.var << "null)"
- << "{"
- << "const " << type << "& id (" << endl;
-
- if (lazy_pointer (mt))
- os << "ptr_traits::object_id< ptr_traits::element_type > (" <<
- member << ")";
- else
- os << "obj_traits::id (ptr_traits::get_ref (" << member << "))";
-
- os << ");"
- << endl;
-
- member = "id";
- }
- else
- {
- type = mi.fq_type ();
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- os << "{";
- }
-
- traits = "sqlite::value_traits<\n "
- + type + ",\n "
- + db_type_id + " >";
- }
-
- return true;
- }
-
- virtual void
- post (member_info& mi)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
{
- if (composite (mi.t))
- os << "}";
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- if (object_pointer (member_utype (mi.m, key_prefix_)))
- {
- os << "}";
-
- if (!null (mi.m, key_prefix_))
- os << "else" << endl
- << "throw null_pointer ();";
- }
-
- os << "}";
- }
}
virtual void
- traverse_composite (member_info& mi)
+ set_null (member_info& mi)
{
- os << "if (" << traits << "::init (" << endl
- << "i." << mi.var << "value," << endl
- << member << "," << endl
- << "sk))" << endl
- << "grew = true;";
+ os << "i." << mi.var << "null = true;";
}
virtual void
@@ -443,8 +291,9 @@ namespace relational
{
os << traits << "::set_image (" << endl
<< "i." << mi.var << "value," << endl
- << "i." << mi.var << "null," << endl
- << member << ");";
+ << "is_null," << endl
+ << member << ");"
+ << "i." << mi.var << "null = is_null;";
}
virtual void
@@ -452,8 +301,9 @@ namespace relational
{
os << traits << "::set_image (" << endl
<< "i." << mi.var << "value," << endl
- << "i." << mi.var << "null," << endl
- << member << ");";
+ << "is_null," << endl
+ << member << ");"
+ << "i." << mi.var << "null = is_null;";
}
virtual void
@@ -463,18 +313,11 @@ namespace relational
<< traits << "::set_image (" << endl
<< "i." << mi.var << "value," << endl
<< "i." << mi.var << "size," << endl
- << "i." << mi.var << "null," << endl
+ << "is_null," << endl
<< member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "grew = grew || (cap != i." << mi.var << "value.capacity ());";
}
-
- private:
- string type;
- string db_type_id;
- string member;
- string traits;
-
- member_database_type_id member_database_type_id_;
};
entry<init_image_member> init_image_member_;
@@ -482,147 +325,21 @@ namespace relational
// init value
//
- struct init_value_member: relational::init_value_member, member_base
+ struct init_value_member: relational::init_value_member_impl<sql_type>,
+ member_base
{
init_value_member (base const& x)
- : member_base::base (x), // virtual base
- base (x),
- member_base (x),
- member_database_type_id_ (base::type_override_,
- base::fq_type_override_,
- base::key_prefix_)
- {
- }
-
- virtual bool
- pre (member_info& mi)
- {
- if (container (mi))
- return false;
-
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- string const& name (mi.m.name ());
- member = "o." + name;
-
- if (mi.cq)
- member = "const_cast< " + mi.fq_type (false) + "& > (" +
- member + ")";
-
- os << "// " << name << endl
- << "//" << endl;
- }
-
- // If this is a wrapped composite value, then we need to
- // "unwrap" it. For simple values this is taken care of
- // by the value_traits specializations.
- //
- if (mi.wrapper != 0 && composite (mi.t))
- {
- // Here we need the wrapper type, not the wrapped type.
- //
- member = "wrapper_traits< " + mi.fq_type (false) + " >::" +
- "set_ref (\n" + member + ")";
- }
-
- if (composite (mi.t))
- traits = "composite_value_traits< " + mi.fq_type () + " >";
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (mt))
- {
- type = "obj_traits::id_type";
- db_type_id = member_database_type_id_.database_type_id (mi.m);
-
- // Handle NULL pointers and extract the id.
- //
- os << "{"
- << "typedef object_traits< " << class_fq_name (*c) <<
- " > obj_traits;"
- << "typedef pointer_traits< " << mi.fq_type () <<
- " > ptr_traits;"
- << endl
- << "if (i." << mi.var << "null)" << endl;
-
- if (null (mi.m, key_prefix_))
- os << member << " = ptr_traits::pointer_type ();";
- else
- os << "throw null_pointer ();";
-
- os << "else"
- << "{"
- << type << " id;";
-
- member = "id";
- }
- else
- {
- type = mi.fq_type ();
- db_type_id = member_database_type_id_.database_type_id (mi.m);
- }
-
- traits = "sqlite::value_traits<\n "
- + type + ",\n "
- + db_type_id + " >";
- }
-
- return true;
- }
-
- virtual void
- post (member_info& mi)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
{
- if (composite (mi.t))
- return;
-
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_utype (mi.m, key_prefix_));
-
- if (object_pointer (mt))
- {
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- member = "o." + mi.m.name ();
-
- if (mi.cq)
- member = "const_cast< " + mi.fq_type (false) + "& > (" +
- member + ")";
- }
-
- if (lazy_pointer (mt))
- os << member << " = ptr_traits::pointer_type (db, 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
- << "db.load< obj_traits::object_type > (id));";
-
- os << "}"
- << "}";
- }
}
virtual void
- traverse_composite (member_info& mi)
+ get_null (member_info& mi)
{
- os << traits << "::init (" << endl
- << member << "," << endl
- << "i." << mi.var << "value," << endl
- << "db);"
- << endl;
+ os << "i." << mi.var << "null";
}
virtual void
@@ -655,14 +372,6 @@ namespace relational
<< "i." << mi.var << "null);"
<< endl;
}
-
- private:
- string type;
- string db_type_id;
- string traits;
- string member;
-
- member_database_type_id member_database_type_id_;
};
entry<init_value_member> init_value_member_;
@@ -680,7 +389,6 @@ namespace relational
};
entry<container_traits> container_traits_;
-
struct class_: relational::class_, context
{
class_ (base const& x): base (x) {}
diff --git a/odb/validator.cxx b/odb/validator.cxx
index b8f7c91..c051487 100644
--- a/odb/validator.cxx
+++ b/odb/validator.cxx
@@ -42,7 +42,7 @@ namespace
// Pass 1.
//
- struct data_member: traversal::data_member
+ struct data_member: traversal::data_member, context
{
data_member (bool& valid)
: valid_ (valid)
@@ -52,45 +52,42 @@ namespace
virtual void
traverse (type& m)
{
- if (context::transient (m))
+ if (transient (m))
return;
count_++;
semantics::names* hint;
- semantics::type& t (context::utype (m, hint));
+ semantics::type& t (utype (m, hint));
if (t.fq_anonymous (hint))
{
- cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " error: unnamed type in data member declaration" << endl;
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: unnamed type in data member declaration" << endl;
- cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " info: use 'typedef' to name this type" << endl;
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " info: use 'typedef' to name this type" << endl;
valid_ = false;
}
// Make sure id or inverse member is not marked readonly since we
- // depend on these three sets not having overlaps. Once we support
- // composite ids, we will also need to make sure there are no
- // nested readonly members (probably move it to pass 2 and use
- // column_count()).
+ // depend on these three sets not having overlaps.
//
- if (m.count ("readonly"))
+ if (readonly (m))
{
- if (m.count ("id"))
+ if (id (m))
{
- cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " error: object id should not be declared readonly" << endl;
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: object id should not be declared readonly" << endl;
valid_ = false;
}
- if (m.count ("inverse"))
+ if (inverse (m))
{
- cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " error: inverse object pointer should not be declared "
- << "readonly" << endl;
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: inverse object pointer should not be declared "
+ << "readonly" << endl;
valid_ = false;
}
@@ -108,9 +105,9 @@ namespace
// Find special members (id, version).
//
- struct special_members: traversal::class_
+ struct special_members: traversal::class_, context
{
- special_members (class_kind kind,
+ special_members (class_kind_type kind,
bool& valid,
semantics::data_member*& id,
semantics::data_member*& optimistic)
@@ -131,7 +128,7 @@ namespace
{
case class_object:
{
- if (!context::object (c))
+ if (!object (c))
return;
break;
}
@@ -141,7 +138,7 @@ namespace
}
case class_composite:
{
- if (!context::composite (c))
+ if (!composite (c))
return;
break;
}
@@ -161,7 +158,7 @@ namespace
}
private:
- struct member: traversal::data_member
+ struct member: traversal::data_member, context
{
member (bool& valid,
semantics::data_member*& id,
@@ -173,17 +170,15 @@ namespace
virtual void
traverse (semantics::data_member& m)
{
- if (m.count ("id"))
+ if (id (m))
{
if (id_ != 0)
{
- cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " error: multiple object id members" << endl;
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: multiple object id members" << endl;
- semantics::data_member& i (*id_);
-
- cerr << i.file () << ":" << i.line () << ":" << i.column ()
- << ": info: previous id member is declared here" << endl;
+ os << id_->file () << ":" << id_->line () << ":" << id_->column ()
+ << ": info: previous id member is declared here" << endl;
valid_ = false;
}
@@ -191,17 +186,17 @@ namespace
id_ = &m;
}
- if (m.count ("version"))
+ if (version (m))
{
if (optimistic_ != 0)
{
- cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " error: multiple version members" << endl;
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: multiple version members" << endl;
semantics::data_member& o (*optimistic_);
- cerr << o.file () << ":" << o.line () << ":" << o.column ()
- << ": info: previous version member is declared here" << endl;
+ os << o.file () << ":" << o.line () << ":" << o.column ()
+ << ": info: previous version member is declared here" << endl;
valid_ = false;
}
@@ -215,7 +210,7 @@ namespace
semantics::data_member*& optimistic_;
};
- class_kind kind_;
+ class_kind_type kind_;
member member_;
traversal::names names_;
traversal::inherits inherits_;
@@ -223,7 +218,7 @@ namespace
//
//
- struct value_type: traversal::type
+ struct value_type: traversal::type, context
{
value_type (bool& valid): valid_ (valid) {}
@@ -241,17 +236,10 @@ namespace
//
//
- struct class1: traversal::class_
+ struct class1: traversal::class_, context
{
- class1 (bool& valid,
- options const& ops,
- semantics::unit& unit,
- value_type& vt)
- : valid_ (valid),
- options_ (ops),
- unit_ (unit),
- vt_ (vt),
- member_ (valid)
+ class1 (bool& valid, value_type& vt)
+ : valid_ (valid), vt_ (vt), member_ (valid)
{
*this >> names_ >> member_;
}
@@ -259,13 +247,13 @@ namespace
virtual void
traverse (type& c)
{
- if (context::object (c))
+ if (object (c))
traverse_object (c);
- else if (context::view (c))
+ else if (view (c))
traverse_view (c);
else
{
- if (context::composite (c))
+ if (composite (c))
traverse_composite (c);
vt_.dispatch (c);
@@ -286,10 +274,10 @@ namespace
if (decl == error_mark_node || TREE_CODE (decl) != BASELINK)
{
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ": "
- << "error: unable to resolve member function '" << name << "' "
- << "specified with '#pragma db callback' for class '"
- << context::class_name (c) << "'" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ": "
+ << "error: unable to resolve member function '" << name << "' "
+ << "specified with '#pragma db callback' for class '"
+ << class_name (c) << "'" << endl;
valid_ = false;
}
@@ -324,25 +312,25 @@ namespace
{
type& b (i->base ());
- if (context::object (b))
+ if (object (b))
base = true;
- else if (context::view (b) || context::composite (b))
+ else if (view (b) || composite (b))
{
// @@ Should we use hint here?
//
- string name (context::class_fq_name (b));
+ string name (class_fq_name (b));
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " error: base class '" << name << "' is a view or value type"
- << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: base class '" << name << "' is a view or value type"
+ << endl;
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " info: object types cannot derive from view or value "
- << "types"
- << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " info: object types cannot derive from view or value "
+ << "types"
+ << endl;
- cerr << b.file () << ":" << b.line () << ":" << b.column () << ":"
- << " info: class '" << name << "' is defined here" << endl;
+ os << b.file () << ":" << b.line () << ":" << b.column () << ":"
+ << " info: class '" << name << "' is defined here" << endl;
valid_ = false;
}
@@ -359,21 +347,21 @@ namespace
if (id == 0)
{
- // An object without an id should either be abstract or
- // explicitly marked as such.
+ // An object without an id should either be abstract or explicitly
+ // marked as such.
//
- if (!(c.count ("id") || context::abstract (c)))
+ if (!(c.count ("id") || abstract (c)))
{
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " error: no data member designated as an object id" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: no data member designated as an object id" << endl;
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " info: use '#pragma db id' to specify an object id member"
- << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " info: use '#pragma db id' to specify an object id member"
+ << endl;
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " info: or explicitly declare that this persistent class "
- << "has no object id" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " info: or explicitly declare that this persistent class "
+ << "has no object id" << endl;
valid_ = false;
}
@@ -387,9 +375,9 @@ namespace
//
if (id->count ("default"))
{
- cerr << id->file () << ":" << id->line () << ":" << id->column ()
- << ": error: object id member cannot have default value"
- << endl;
+ os << id->file () << ":" << id->line () << ":" << id->column ()
+ << ": error: object id member cannot have default value"
+ << endl;
valid_ = false;
}
@@ -399,8 +387,8 @@ namespace
//
if (id->count ("null"))
{
- cerr << id->file () << ":" << id->line () << ":" << id->column ()
- << ": error: object id member cannot be null" << endl;
+ os << id->file () << ":" << id->line () << ":" << id->column ()
+ << ": error: object id member cannot be null" << endl;
valid_ = false;
}
@@ -416,13 +404,13 @@ namespace
//
if (&optimistic->scope () == &c && !c.count ("optimistic"))
{
- cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " error: version data member in a class not declared "
- << "optimistic" << endl;
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: version data member in a class not declared "
+ << "optimistic" << endl;
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " info: use '#pragma db optimistic' to declare this "
- << "class optimistic" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " info: use '#pragma db optimistic' to declare this "
+ << "class optimistic" << endl;
valid_ = false;
}
@@ -431,8 +419,8 @@ namespace
//
if (id == 0)
{
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " error: optimistic class without an object id" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: optimistic class without an object id" << endl;
valid_ = false;
}
@@ -442,34 +430,33 @@ namespace
//
if (id != 0 && &id->scope () != &optimistic->scope ())
{
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " error: object id and version members are in different "
- << "classes" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: object id and version members are in different "
+ << "classes" << endl;
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " info: object id and version members must be in the same "
- << "class" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " info: object id and version members must be in the same "
+ << "class" << endl;
- cerr << id->file () << ":" << id->line () << ":" << id->column ()
- << ": info: object id member is declared here" << endl;
+ os << id->file () << ":" << id->line () << ":" << id->column ()
+ << ": info: object id member is declared here" << endl;
- cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " error: version member is declared here" << endl;
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: version member is declared here" << endl;
valid_ = false;
}
// Make sure this class is not readonly.
//
- if (c.count ("readonly"))
+ if (readonly (c))
{
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " error: optimistic class cannot be readonly" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: optimistic class cannot be readonly" << endl;
valid_ = false;
}
-
// This takes care of also marking derived classes as optimistic.
//
c.set ("optimistic-member", optimistic);
@@ -481,12 +468,12 @@ namespace
//
if (c.count ("optimistic"))
{
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " error: optimistic class without a version member" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: optimistic class without a version member" << endl;
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " info: use '#pragma db version' to declare on of the "
- << "data members as a version" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " info: use '#pragma db version' to declare on of the "
+ << "data members as a version" << endl;
valid_ = false;
}
@@ -499,8 +486,8 @@ namespace
if (member_.count_ == 0 && !base)
{
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " error: no persistent data members in the class" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: no persistent data members in the class" << endl;
valid_ = false;
}
@@ -511,16 +498,16 @@ namespace
{
// Views require query support.
//
- if (!options_.generate_query ())
+ if (!options.generate_query ())
{
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " error: query support is required when using views"
- << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: query support is required when using views"
+ << endl;
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " info: use the --generate-query option to enable query "
- << "support"
- << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " info: use the --generate-query option to enable query "
+ << "support"
+ << endl;
valid_ = false;
}
@@ -533,26 +520,24 @@ namespace
{
type& b (i->base ());
- if (context::object (b) ||
- context::view (b) ||
- context::composite (b))
+ if (object (b) || view (b) || composite (b))
{
// @@ Should we use hint here?
//
- string name (context::class_fq_name (b));
+ string name (class_fq_name (b));
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " error: base class '" << name << "' is an object, "
- << "view, or value type"
- << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: base class '" << name << "' is an object, "
+ << "view, or value type"
+ << endl;
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " info: view types cannot derive from view, object or "
- << "value types"
- << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " info: view types cannot derive from view, object or "
+ << "value types"
+ << endl;
- cerr << b.file () << ":" << b.line () << ":" << b.column () << ":"
- << " info: class '" << name << "' is defined here" << endl;
+ os << b.file () << ":" << b.line () << ":" << b.column () << ":"
+ << " info: class '" << name << "' is defined here" << endl;
valid_ = false;
}
@@ -569,9 +554,9 @@ namespace
if (id != 0)
{
- cerr << id->file () << ":" << id->line () << ":" << id->column ()
- << ": error: view type data member cannot be designated as an "
- << "object id" << endl;
+ os << id->file () << ":" << id->line () << ":" << id->column ()
+ << ": error: view type data member cannot be designated as an "
+ << "object id" << endl;
valid_ = false;
}
@@ -580,9 +565,9 @@ namespace
{
semantics::data_member& o (*optimistic);
- cerr << o.file () << ":" << o.line () << ":" << o.column ()
- << ": error: view type data member cannot be designated as a "
- << "version" << endl;
+ os << o.file () << ":" << o.line () << ":" << o.column ()
+ << ": error: view type data member cannot be designated as a "
+ << "version" << endl;
valid_ = false;
}
@@ -594,8 +579,8 @@ namespace
if (member_.count_ == 0)
{
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " error: no persistent data members in the class" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: no persistent data members in the class" << endl;
valid_ = false;
}
@@ -612,25 +597,25 @@ namespace
{
type& b (i->base ());
- if (context::composite (b))
+ if (composite (b))
base = true;
- else if (context::object (b) || context::view (b))
+ else if (object (b) || view (b))
{
// @@ Should we use hint here?
//
- string name (context::class_fq_name (b));
+ string name (class_fq_name (b));
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " error: base class '" << name << "' is a view or object "
- << "type"
- << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: base class '" << name << "' is a view or object "
+ << "type"
+ << endl;
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " info: composite value types cannot derive from object "
- << "or view types" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " info: composite value types cannot derive from object "
+ << "or view types" << endl;
- cerr << b.file () << ":" << b.line () << ":" << b.column () << ":"
- << " info: class '" << name << "' is defined here" << endl;
+ os << b.file () << ":" << b.line () << ":" << b.column () << ":"
+ << " info: class '" << name << "' is defined here" << endl;
valid_ = false;
}
@@ -647,9 +632,9 @@ namespace
if (id != 0)
{
- cerr << id->file () << ":" << id->line () << ":" << id->column ()
- << ": error: value type data member cannot be designated as an "
- << "object id" << endl;
+ os << id->file () << ":" << id->line () << ":" << id->column ()
+ << ": error: value type data member cannot be designated as an "
+ << "object id" << endl;
valid_ = false;
}
@@ -658,9 +643,9 @@ namespace
{
semantics::data_member& o (*optimistic);
- cerr << o.file () << ":" << o.line () << ":" << o.column ()
- << ": error: value type data member cannot be designated as a "
- << "version" << endl;
+ os << o.file () << ":" << o.line () << ":" << o.column ()
+ << ": error: value type data member cannot be designated as a "
+ << "version" << endl;
valid_ = false;
}
@@ -672,16 +657,14 @@ namespace
if (member_.count_ == 0 && !base)
{
- cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
- << " error: no persistent data members in the class" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: no persistent data members in the class" << endl;
valid_ = false;
}
}
bool& valid_;
- options const& options_;
- semantics::unit& unit_;
value_type& vt_;
data_member member_;
@@ -720,15 +703,80 @@ namespace
}
virtual void
+ traverse_pointer (semantics::data_member& m, semantics::class_&)
+ {
+ if (inverse (m))
+ {
+ semantics::data_member& dm (dm_ != 0 ? *dm_ : m);
+
+ os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
+ << " error: inverse object pointer member '" << member_prefix_
+ << m.name () << "' in an object without an object id" << endl;
+
+ valid_ = false;
+ }
+ }
+
+ virtual void
+ traverse_container (semantics::data_member& m, semantics::type&)
+ {
+ semantics::data_member& dm (dm_ != 0 ? *dm_ : m);
+
+ os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
+ << " error: container member '" << member_prefix_ << m.name ()
+ << "' in an object without an object id" << endl;
+
+ valid_ = false;
+ }
+
+ virtual void
+ traverse_composite (semantics::data_member* m, semantics::class_& c)
+ {
+ semantics::data_member* old_dm (dm_);
+
+ if (dm_ == 0)
+ dm_ = m;
+
+ object_members_base::traverse_composite (m, c);
+
+ dm_ = old_dm;
+ }
+
+ private:
+ bool& valid_;
+ semantics::data_member* dm_; // Direct object data member.
+ };
+
+ struct composite_id_members: object_members_base
+ {
+ composite_id_members (bool& valid)
+ : object_members_base (false, false, true), valid_ (valid), dm_ (0)
+ {
+ }
+
+ virtual void
+ traverse_pointer (semantics::data_member& m, semantics::class_&)
+ {
+ semantics::data_member& dm (dm_ != 0 ? *dm_ : m);
+
+ os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
+ << " error: object pointer member '" << member_prefix_ << m.name ()
+ << "' in a composite value type that is used as an object id" << endl;
+
+ valid_ = false;
+ }
+
+ virtual void
traverse_simple (semantics::data_member& m)
{
- if (m.count ("inverse"))
+ if (readonly (member_path_, member_scope_))
{
semantics::data_member& dm (dm_ != 0 ? *dm_ : m);
- cerr << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
- << " error: inverse object pointer member '" << member_prefix_
- << m.name () << "' in an object without an object id" << endl;
+ os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
+ << " error: readonly member '" << member_prefix_ << m.name ()
+ << "' in a composite value type that is used as an object id"
+ << endl;
valid_ = false;
}
@@ -739,9 +787,9 @@ namespace
{
semantics::data_member& dm (dm_ != 0 ? *dm_ : m);
- cerr << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
- << " error: container member '" << member_prefix_ << m.name ()
- << "' in an object without an object id" << endl;
+ os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
+ << " error: container member '" << member_prefix_ << m.name ()
+ << "' in a composite value type that is used as an object id" << endl;
valid_ = false;
}
@@ -761,7 +809,7 @@ namespace
private:
bool& valid_;
- semantics::data_member* dm_; // Direct view data member.
+ semantics::data_member* dm_; // Direct composite member.
};
struct view_members: object_members_base
@@ -774,16 +822,16 @@ namespace
virtual void
traverse_simple (semantics::data_member& m)
{
- if (context::object_pointer (utype (m)))
+ if (object_pointer (utype (m)))
{
semantics::data_member& dm (dm_ != 0 ? *dm_ : m);
- cerr << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
- << " error: view data member '" << member_prefix_ << m.name ()
- << "' is an object pointer" << endl;
+ os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
+ << " error: view data member '" << member_prefix_ << m.name ()
+ << "' is an object pointer" << endl;
- cerr << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
- << ": info: views cannot contain object pointers" << endl;
+ os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
+ << ": info: views cannot contain object pointers" << endl;
valid_ = false;
}
@@ -794,12 +842,12 @@ namespace
{
semantics::data_member& dm (dm_ != 0 ? *dm_ : m);
- cerr << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
- << " error: view data member '" << member_prefix_ << m.name ()
- << "' is a container" << endl;
+ os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
+ << " error: view data member '" << member_prefix_ << m.name ()
+ << "' is a container" << endl;
- cerr << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
- << ": info: views cannot contain containers" << endl;
+ os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
+ << ": info: views cannot contain containers" << endl;
valid_ = false;
}
@@ -824,36 +872,175 @@ namespace
//
//
- struct class2: traversal::class_
+ struct class2: traversal::class_, context
{
- class2 (bool& valid, options const& ops, semantics::unit& unit)
+ class2 (bool& valid)
: valid_ (valid),
- options_ (ops),
- unit_ (unit),
object_no_id_members_ (valid),
+ composite_id_members_ (valid),
view_members_ (valid)
{
+ // Find the has_lt_operator function template..
+ //
+ has_lt_operator_ = 0;
+
+ tree odb (
+ lookup_qualified_name (
+ global_namespace, get_identifier ("odb"), false, false));
+
+ if (odb != error_mark_node)
+ {
+ tree compiler (
+ lookup_qualified_name (
+ odb, get_identifier ("compiler"), false, false));
+
+ if (compiler != error_mark_node)
+ {
+ has_lt_operator_ = lookup_qualified_name (
+ compiler, get_identifier ("has_lt_operator"), false, false);
+
+ if (has_lt_operator_ != error_mark_node)
+ has_lt_operator_ = OVL_CURRENT (has_lt_operator_);
+ else
+ {
+ os << unit.file () << ": error: unable to resolve has_lt_operator "
+ << "function template inside odb::compiler" << endl;
+ has_lt_operator_ = 0;
+ }
+ }
+ else
+ os << unit.file () << ": error: unable to resolve compiler "
+ << "namespace inside odb" << endl;
+ }
+ else
+ os << unit.file () << ": error: unable to resolve odb namespace"
+ << endl;
+
+ if (has_lt_operator_ == 0)
+ valid_ = false;
}
virtual void
traverse (type& c)
{
- if (context::object (c))
+ if (object (c))
traverse_object (c);
- else if (context::view (c))
+ else if (view (c))
traverse_view (c);
- else if (context::composite (c))
+ else if (composite (c))
traverse_composite (c);
}
virtual void
traverse_object (type& c)
{
- if (context::id_member (c) == 0 && !context::abstract (c))
+ semantics::data_member* id (id_member (c));
+
+ if (id != 0)
{
- // Make sure we don't have any containers or inverse pointers.
- //
- object_no_id_members_.traverse (c);
+ if (semantics::class_* c = composite_wrapper (utype (*id)))
+ {
+ // Composite id cannot be auto.
+ //
+ if (auto_ (*id))
+ {
+ os << id->file () << ":" << id->line () << ":" << id->column ()
+ << ": error: composite id cannot be automatically assigned"
+ << endl;
+
+ valid_ = false;
+ }
+
+ // Make sure we don't have any containers or pointers in this
+ // composite value type.
+ //
+ if (valid_)
+ {
+ composite_id_members_.traverse (*c);
+
+ if (!valid_)
+ os << id->file () << ":" << id->line () << ":" << id->column ()
+ << ": info: composite id is defined here" << endl;
+ }
+
+ // Check that the composite value type is default-constructible.
+ //
+ if (!c->default_ctor ())
+ {
+ os << c->file () << ":" << c->line () << ":" << c->column ()
+ << ": error: composite value type that is used as object id "
+ << "is not default-constructible" << endl;
+
+ os << c->file () << ":" << c->line () << ":" << c->column ()
+ << ": info: provide default constructor for this value type"
+ << endl;
+
+ os << id->file () << ":" << id->line () << ":" << id->column ()
+ << ": info: composite id is defined here" << endl;
+
+ valid_ = false;
+ }
+
+ // Check that composite values can be compared (used in session).
+ //
+ if (has_lt_operator_ != 0)
+ {
+ tree args (make_tree_vec (1));
+ TREE_VEC_ELT (args, 0) = c->tree_node ();
+
+ tree inst (
+ instantiate_template (
+ has_lt_operator_, args, tf_none));
+
+ bool v (inst != error_mark_node);
+
+ if (v &&
+ DECL_TEMPLATE_INSTANTIATION (inst) &&
+ !DECL_TEMPLATE_INSTANTIATED (inst))
+ {
+ // Instantiate this function template to see if the value type
+ // provides operator<. Unfortunately, GCC instantiate_decl()
+ // does not provide any control over the diagnostics it issues
+ // in case of an error. To work around this, we are going to
+ // temporarily redirect diagnostics to /dev/null, which is
+ // where asm_out_file points to (see plugin.cxx).
+ //
+ int ec (errorcount);
+ FILE* s (global_dc->printer->buffer->stream);
+ global_dc->printer->buffer->stream = asm_out_file;
+
+ instantiate_decl (inst, false, false);
+
+ global_dc->printer->buffer->stream = s;
+ v = (ec == errorcount);
+ }
+
+ if (!v)
+ {
+ os << c->file () << ":" << c->line () << ":" << c->column ()
+ << ": error: composite value type that is used as object id "
+ << "does not support the less than (<) comparison"
+ << endl;
+
+ os << c->file () << ":" << c->line () << ":" << c->column ()
+ << ": info: provide operator< for this value type" << endl;
+
+ os << id->file () << ":" << id->line () << ":" << id->column ()
+ << ": info: composite id is defined here" << endl;
+
+ valid_ = false;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (!abstract (c))
+ {
+ // Make sure we don't have any containers or inverse pointers.
+ //
+ object_no_id_members_.traverse (c);
+ }
}
}
@@ -871,10 +1058,10 @@ namespace
}
bool& valid_;
- options const& options_;
- semantics::unit& unit_;
+ tree has_lt_operator_;
object_no_id_members object_no_id_members_;
+ composite_id_members composite_id_members_;
view_members view_members_;
};
}
@@ -897,7 +1084,7 @@ validate (options const& ops,
typedefs1 unit_typedefs (unit_declares);
traversal::namespace_ ns;
value_type vt (valid);
- class1 c (valid, ops, u, vt);
+ class1 c (valid, vt);
unit >> unit_defines >> ns;
unit_defines >> c;
@@ -921,7 +1108,7 @@ validate (options const& ops,
traversal::defines unit_defines;
typedefs unit_typedefs (true);
traversal::namespace_ ns;
- class2 c (valid, ops, u);
+ class2 c (valid);
unit >> unit_defines >> ns;
unit_defines >> c;