summaryrefslogtreecommitdiff
path: root/odb/relational
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-10-25 10:35:36 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-10-25 10:35:36 +0200
commitd1ad30f7a517e69bc87d1347224f1c9ab38493b3 (patch)
tree95189ae91fcce6366f0a121f67b483f3c1b962e7 /odb/relational
parent7fc555e53f0a03c93fe31ad9850b1e5d885c44f6 (diff)
Static multi-database support
Add new options (--multi-database, --default-database). Generate common code to -odb.?xx files and database-specific to -odb-<db>.?xx.
Diffstat (limited to 'odb/relational')
-rw-r--r--odb/relational/common.hxx2
-rw-r--r--odb/relational/header.cxx274
-rw-r--r--odb/relational/header.hxx3
-rw-r--r--odb/relational/inline.hxx180
-rw-r--r--odb/relational/processor.cxx1102
-rw-r--r--odb/relational/source.cxx4
-rw-r--r--odb/relational/validator.cxx296
7 files changed, 351 insertions, 1510 deletions
diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx
index 26e8197..b951d15 100644
--- a/odb/relational/common.hxx
+++ b/odb/relational/common.hxx
@@ -336,7 +336,7 @@ namespace relational
static B*
create (B const& prototype)
{
- database db (context::current ().options.database ());
+ database db (context::current ().options.database ()[0]);
if (map_ != 0)
{
diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx
index c6fc9a5..1295106 100644
--- a/odb/relational/header.cxx
+++ b/odb/relational/header.cxx
@@ -13,15 +13,14 @@ traverse_object (type& c)
using semantics::data_member;
data_member* id (id_member (c));
- bool auto_id (id ? id->count ("auto") : false);
- bool base_id (id ? &id->scope () != &c : false); // Comes from base.
+ bool auto_id (id && auto_ (*id));
+ bool base_id (id && &id->scope () != &c); // Comes from base.
data_member* optimistic (context::optimistic (c));
type* poly_root (polymorphic (c));
bool poly (poly_root != 0);
bool poly_derived (poly && poly_root != &c);
- type* poly_base (poly_derived ? &polymorphic_base (c) : 0);
data_member* discriminator (poly ? context::discriminator (*poly_root) : 0);
bool abst (abstract (c));
@@ -33,196 +32,6 @@ traverse_object (type& c)
os << "// " << class_name (c) << endl
<< "//" << endl;
- // class_traits
- //
- os << "template <>" << endl
- << "struct class_traits< " << type << " >"
- << "{"
- << "static const class_kind kind = class_object;"
- << "};";
-
- // object_traits
- //
- os << "template <>" << endl
- << "class access::object_traits< " << type << " >"
- << "{"
- << "public:" << endl;
-
- // object_type & pointer_type
- //
- os << "typedef " << type << " object_type;"
- << "typedef " << c.get<string> ("object-pointer") << " pointer_type;"
- << "typedef odb::pointer_traits<pointer_type> pointer_traits;"
- << endl;
-
- // polymorphic, root_type, base_type, etc.
- //
- os << "static const bool polymorphic = " << (poly ? "true" : "false") << ";"
- << endl;
-
- if (poly)
- {
- os << "typedef " << class_fq_name (*poly_root) << " root_type;";
-
- if (poly_derived)
- {
- os << "typedef " << class_fq_name (*poly_base) << " base_type;"
- << "typedef object_traits<root_type>::discriminator_type " <<
- "discriminator_type;"
- << "typedef polymorphic_concrete_info<root_type> info_type;";
-
- if (abst)
- os << "typedef polymorphic_abstract_info<root_type> " <<
- "abstract_info_type;";
-
- // Calculate our hierarchy depth (number of classes).
- //
- size_t depth (polymorphic_depth (c));
-
- os << endl
- << "static const std::size_t depth = " << depth << "UL;";
- }
- else
- {
- semantics::names* hint;
- semantics::type& t (utype (*discriminator, hint));
-
- os << "typedef " << t.fq_name (hint) << " discriminator_type;"
- << "typedef polymorphic_map<object_type> map_type;"
- << "typedef polymorphic_concrete_info<object_type> info_type;";
-
- if (abst)
- os << "typedef polymorphic_abstract_info<object_type> " <<
- "abstract_info_type;";
-
- os << endl
- << "static const std::size_t depth = 1UL;";
- }
-
- os << endl;
- }
-
- // id_type, version_type, etc.
- //
- if (id != 0)
- {
- if (base_id)
- {
- semantics::class_& b (
- dynamic_cast<semantics::class_&> (id->scope ()));
- string const& type (class_fq_name (b));
-
- os << "typedef object_traits< " << type << " >::id_type id_type;";
-
- if (optimistic != 0)
- os << "typedef object_traits< " << type << " >::version_type " <<
- "version_type;";
-
- os << endl;
-
- if (poly_derived)
- os << "static const bool auto_id = false;";
- else
- os << "static const bool auto_id = object_traits< " << type <<
- " >::auto_id;";
- }
- else
- {
- {
- semantics::names* hint;
- semantics::type& t (utype (*id, hint));
- os << "typedef " << t.fq_name (hint) << " id_type;";
- }
-
- if (optimistic != 0)
- {
- semantics::names* hint;
- semantics::type& t (utype (*optimistic, hint));
- os << "typedef " << t.fq_name (hint) << " version_type;";
- }
-
- os << endl
- << "static const bool auto_id = " << (auto_id ? "true;" : "false;");
- }
-
- os << endl;
- }
- else if (!reuse_abst)
- {
- // Object without id.
- //
- os << "typedef void id_type;"
- << endl
- << "static const bool auto_id = false;"
- << endl;
- }
-
- // abstract
- //
- os << "static const bool abstract = " << (abst ? "true" : "false") << ";"
- << endl;
-
- // id ()
- //
- if (id != 0 || !reuse_abst)
- {
- // We want to generate a dummy void id() accessor even if this
- // object has no id to help us in the runtime. This way we can
- // write generic code that will work for both void and non-void
- // ids.
- //
- os << "static id_type" << endl
- << "id (const object_type&);"
- << endl;
- }
-
- if (!reuse_abst)
- {
- // Cache traits typedefs.
- //
- if (id == 0)
- {
- os << "typedef" << endl
- << "no_id_pointer_cache_traits<pointer_type>" << endl
- << "pointer_cache_traits;"
- << endl
- << "typedef" << endl
- << "no_id_reference_cache_traits<object_type>" << endl
- << "reference_cache_traits;"
- << endl;
- }
- else
- {
- char const* p (session (c) ? "odb::" : "no_op_");
-
- if (poly_derived)
- {
- os << "typedef" << endl
- << p << "pointer_cache_traits<" <<
- "object_traits<root_type>::pointer_type>" << endl
- << "pointer_cache_traits;"
- << endl
- << "typedef" << endl
- << p << "reference_cache_traits<root_type>" << endl
- << "reference_cache_traits;"
- << endl;
- }
- else
- {
- os << "typedef" << endl
- << p << "pointer_cache_traits<pointer_type>" << endl
- << "pointer_cache_traits;"
- << endl
- << "typedef" << endl
- << p << "reference_cache_traits<object_type>" << endl
- << "reference_cache_traits;"
- << endl;
- }
- }
- }
-
- os << "};";
-
// pointer_query_columns & query_columns
//
if (options.generate_query ())
@@ -584,16 +393,6 @@ traverse_object (type& c)
// Functions (concrete).
//
- // callback ()
- //
- os << "static void" << endl
- << "callback (database&, object_type&, callback_event);"
- << endl;
-
- os << "static void" << endl
- << "callback (database&, const object_type&, callback_event);"
- << endl;
-
// persist ()
//
os << "static void" << endl
@@ -814,13 +613,17 @@ traverse_object (type& c)
//
// Note that it is not generated for reuse-abstract classes.
//
- os << "template <>" << endl
- << "class access::object_traits_impl< " << type << ", " <<
- "id_default >:" << endl
- << " public access::object_traits_impl< " << type << ", " <<
- "id_" << db << " >"
- << "{"
- << "};";
+ if (options.default_database_specified () &&
+ options.default_database () == db)
+ {
+ os << "template <>" << endl
+ << "class access::object_traits_impl< " << type << ", " <<
+ "id_default >:" << endl
+ << " public access::object_traits_impl< " << type << ", " <<
+ "id_" << db << " >"
+ << "{"
+ << "};";
+ }
}
void relational::header::class1::
@@ -831,28 +634,6 @@ traverse_view (type& c)
os << "// " << class_name (c) << endl
<< "//" << endl;
- // class_traits
- //
- os << "template <>" << endl
- << "struct class_traits< " << type << " >"
- << "{"
- << "static const class_kind kind = class_view;"
- << "};";
-
- // view_traits
- //
- os << "template <>" << endl
- << "class access::view_traits< " << type << " >"
- << "{"
- << "public:" << endl;
-
- // view_type & pointer_type
- //
- os << "typedef " << type << " view_type;"
- << "typedef " << c.get<string> ("object-pointer") << " pointer_type;";
-
- os << "};";
-
// view_traits_impl
//
os << "template <>" << endl
@@ -933,12 +714,6 @@ traverse_view (type& c)
// Functions.
//
- // callback ()
- //
- os << "static void" << endl
- << "callback (database&, view_type&, callback_event);"
- << endl;
-
// query ()
//
if (!options.omit_unprepared ())
@@ -963,12 +738,17 @@ traverse_view (type& c)
// view_traits_impl< , id_default>
//
- os << "template <>" << endl
- << "class access::view_traits_impl< " << type << ", id_default >:" << endl
- << " public access::view_traits_impl< " << type << ", " <<
- "id_" << db << " >"
- << "{"
- << "};";
+ if (options.default_database_specified () &&
+ options.default_database () == db)
+ {
+ os << "template <>" << endl
+ << "class access::view_traits_impl< " << type << ", " <<
+ "id_default >:" << endl
+ << " public access::view_traits_impl< " << type << ", " <<
+ "id_" << db << " >"
+ << "{"
+ << "};";
+ }
}
void relational::header::class1::
@@ -980,12 +760,6 @@ traverse_composite (type& c)
<< "//" << endl;
os << "template <>" << endl
- << "struct class_traits< " << type << " >"
- << "{"
- << "static const class_kind kind = class_composite;"
- << "};";
-
- os << "template <>" << endl
<< "class access::composite_value_traits< " << type << ", " <<
"id_" << db << " >"
<< "{"
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index 75cee16..c0e1e89 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -1233,8 +1233,7 @@ namespace relational
virtual void
generate ()
{
- os << "#include <odb/details/buffer.hxx>" << endl
- << "#include <odb/details/unused.hxx>" << endl;
+ os << "#include <odb/details/buffer.hxx>" << endl;
if (options.generate_query ())
os << "#include <odb/details/shared-ptr.hxx>" << endl;
diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx
index 7e70ab1..466e348 100644
--- a/odb/relational/inline.hxx
+++ b/odb/relational/inline.hxx
@@ -14,68 +14,6 @@ namespace relational
namespace inline_
{
//
- //
- struct callback_calls: traversal::class_, virtual context
- {
- typedef callback_calls base;
-
- callback_calls ()
- {
- *this >> inherits_ >> *this;
- }
-
- callback_calls (callback_calls const&)
- : root_context (), //@@ -Wextra
- context ()
- {
- *this >> inherits_ >> *this;
- }
-
- virtual void
- traverse (type& c, bool constant)
- {
- const_ = constant;
- traverse (c);
- }
-
- virtual void
- traverse (type& c)
- {
- bool obj (object (c));
-
- // Ignore transient bases.
- //
- if (!(obj || view (c)))
- return;
-
- if (c.count ("callback"))
- {
- string name (c.get<string> ("callback"));
-
- // In case of the const instance, we only generate the call if
- // there is a const callback.
- //
- string const& type (class_fq_name (c));
-
- if (const_)
- {
- if (c.count ("callback-const"))
- os << "static_cast< const " << type << "& > (x)." <<
- name << " (e, db);";
- }
- else
- os << "static_cast< " << type << "& > (x)." << name << " (e, db);";
- }
- else if (obj)
- inherits (c);
- }
-
- protected:
- bool const_;
- traversal::inherits inherits_;
- };
-
- //
// get/set null (composite value only)
//
@@ -211,7 +149,7 @@ namespace relational
if (object (c))
traverse_object (c);
- if (view (c))
+ else if (view (c))
traverse_view (c);
else if (composite (c))
traverse_composite (c);
@@ -228,11 +166,11 @@ namespace relational
traverse_object (type& c)
{
semantics::data_member* id (id_member (c));
- bool base_id (id ? &id->scope () != &c : false); // Comes from base.
+ bool base_id (id && &id->scope () != &c); // Comes from base.
semantics::data_member* optimistic (context::optimistic (c));
- // Base class the contains the object id and version for optimistic
+ // Base class that contains the object id and version for optimistic
// concurrency.
//
type* base (
@@ -246,47 +184,13 @@ namespace relational
bool reuse_abst (abst && !poly);
string const& type (class_fq_name (c));
- string traits ("access::object_traits< " + type + " >");
- string traits_impl ("access::object_traits_impl< " + type +
- ", id_" + db.string () + " >");
+ string traits ("access::object_traits_impl< " + type + ", id_" +
+ db.string () + " >");
os << "// " << class_name (c) << endl
<< "//" << endl
<< endl;
- // id (object_type)
- //
- if (id != 0 || !reuse_abst)
- {
- os << "inline" << endl
- << traits << "::id_type" << endl
- << traits << "::" << endl
- << "id (const object_type&" << (id != 0 ? " o" : "") << ")"
- << "{";
-
- if (id != 0)
- {
- if (base_id)
- os << "return object_traits< " << class_fq_name (*base) <<
- " >::id (o);";
- else
- {
- // Get the id using the accessor expression. If this is not
- // a synthesized expression, then output its location for
- // easier error tracking.
- //
- member_access& ma (id->get<member_access> ("get"));
-
- if (!ma.synthesized)
- os << "// From " << location_string (ma.loc, true) << endl;
-
- os << "return " << ma.translate ("o") << ";";
- }
- }
-
- os << "}";
- }
-
object_extra (c);
if (id != 0 && base_id)
@@ -298,8 +202,8 @@ namespace relational
if (options.generate_query ())
{
os << "inline" << endl
- << traits_impl << "::id_type" << endl
- << traits_impl << "::" << endl
+ << traits << "::id_type" << endl
+ << traits << "::" << endl
<< "id (const image_type& i)"
<< "{"
<< "return object_traits_impl< " << class_fq_name (*base) <<
@@ -312,8 +216,8 @@ namespace relational
if (optimistic != 0)
{
os << "inline" << endl
- << traits_impl << "::version_type" << endl
- << traits_impl << "::" << endl
+ << traits << "::version_type" << endl
+ << traits << "::" << endl
<< "version (const image_type& i)"
<< "{"
<< "return object_traits_impl< " << class_fq_name (*base) <<
@@ -325,7 +229,7 @@ namespace relational
// bind (id_image_type)
//
os << "inline" << endl
- << "void " << traits_impl << "::" << endl
+ << "void " << traits << "::" << endl
<< "bind (" << bind_vector << " b, id_image_type& i" <<
(optimistic != 0 ? ", bool bv" : "") << ")"
<< "{"
@@ -334,7 +238,7 @@ namespace relational
<< "}";
os << "inline" << endl
- << "void " << traits_impl << "::" << endl
+ << "void " << traits << "::" << endl
<< "init (id_image_type& i, const id_type& id" <<
(optimistic != 0 ? ", const version_type* v" : "") << ")"
<< "{"
@@ -350,7 +254,7 @@ namespace relational
// check_version
//
os << "inline" << endl
- << "bool " << traits_impl << "::" << endl
+ << "bool " << traits << "::" << endl
<< "check_version (const std::size_t* v, const image_type& i)"
<< "{"
<< "return ";
@@ -370,7 +274,7 @@ namespace relational
// update_version
//
os << "inline" << endl
- << "void " << traits_impl << "::" << endl
+ << "void " << traits << "::" << endl
<< "update_version (std::size_t* v, const image_type& i, " <<
db << "::binding* b)"
<< "{";
@@ -394,7 +298,6 @@ namespace relational
os << "}";
}
- //
// The rest does not apply to reuse-abstract objects.
//
if (reuse_abst)
@@ -405,7 +308,7 @@ namespace relational
if (id != 0 && !poly && optimistic == 0)
{
os << "inline" << endl
- << "void " << traits_impl << "::" << endl
+ << "void " << traits << "::" << endl
<< "erase (database& db, const object_type& obj)"
<< "{"
<< "callback (db, obj, callback_event::pre_erase);"
@@ -414,37 +317,12 @@ namespace relational
<< "}";
}
- // callback ()
- //
- os << "inline" << endl
- << "void " << traits_impl << "::" << endl
- << "callback (database& db, object_type& x, callback_event e)"
- << endl
- << "{"
- << "ODB_POTENTIALLY_UNUSED (db);"
- << "ODB_POTENTIALLY_UNUSED (x);"
- << "ODB_POTENTIALLY_UNUSED (e);"
- << endl;
- callback_calls_->traverse (c, false);
- os << "}";
-
- os << "inline" << endl
- << "void " << traits_impl << "::" << endl
- << "callback (database& db, const object_type& x, callback_event e)"
- << "{"
- << "ODB_POTENTIALLY_UNUSED (db);"
- << "ODB_POTENTIALLY_UNUSED (x);"
- << "ODB_POTENTIALLY_UNUSED (e);"
- << endl;
- callback_calls_->traverse (c, true);
- os << "}";
-
// load_()
//
if (id != 0 && !(poly_derived || has_a (c, test_container)))
{
os << "inline" << endl
- << "void " << traits_impl << "::" << endl
+ << "void " << traits << "::" << endl
<< "load_ (";
if (poly && !poly_derived)
@@ -462,8 +340,8 @@ namespace relational
// root_image ()
//
os << "inline" << endl
- << traits_impl << "::root_traits::image_type&" << endl
- << traits_impl << "::" << endl
+ << traits << "::root_traits::image_type&" << endl
+ << traits << "::" << endl
<< "root_image (image_type& i)"
<< "{";
@@ -477,8 +355,8 @@ namespace relational
// clone_image ()
//
os << "inline" << endl
- << traits_impl << "::image_type*" << endl
- << traits_impl << "::" << endl
+ << traits << "::image_type*" << endl
+ << traits << "::" << endl
<< "clone_image (const image_type& i)"
<< "{";
@@ -496,7 +374,7 @@ namespace relational
// copy_image ()
//
os << "inline" << endl
- << "void " << traits_impl << "::" << endl
+ << "void " << traits << "::" << endl
<< "copy_image (image_type& d, const image_type& s)"
<< "{";
@@ -513,7 +391,7 @@ namespace relational
// free_image ()
//
os << "inline" << endl
- << "void " << traits_impl << "::" << endl
+ << "void " << traits << "::" << endl
<< "free_image (image_type* i)"
<< "{";
@@ -542,20 +420,6 @@ namespace relational
<< endl;
view_extra (c);
-
- // callback ()
- //
- os << "inline" << endl
- << "void " << traits << "::" << endl
- << "callback (database& db, view_type& x, callback_event e)"
- << endl
- << "{"
- << "ODB_POTENTIALLY_UNUSED (db);"
- << "ODB_POTENTIALLY_UNUSED (x);"
- << "ODB_POTENTIALLY_UNUSED (e);"
- << endl;
- callback_calls_->traverse (c, false);
- os << "}";
}
virtual void
@@ -604,8 +468,6 @@ namespace relational
}
private:
- instance<callback_calls> callback_calls_;
-
instance<null_base> get_null_base_;
traversal::inherits get_null_base_inherits_;
instance<null_member> get_null_member_;
diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx
index f000858..5100739 100644
--- a/odb/relational/processor.cxx
+++ b/odb/relational/processor.cxx
@@ -305,497 +305,14 @@ namespace relational
throw operation_failed ();
}
- process_access (m, "get");
- process_access (m, "set");
- process_index (m);
- }
-
- //
- // Process member access expressions.
- //
-
- enum found_type
- {
- found_none,
- found_some, // Found something but keep looking for a better one.
- found_best
- };
-
- // Check if a function is a suitable accessor for this member.
- //
- found_type
- check_accessor (semantics::data_member& m,
- tree f,
- string const& n,
- member_access& ma,
- bool strict)
- {
- // Must be const.
- //
- if (!DECL_CONST_MEMFUNC_P (f))
- return found_none;
-
- // Accessor is a function with no arguments (other than 'this').
- //
- if (DECL_CHAIN (DECL_ARGUMENTS (f)) != NULL_TREE)
- return found_none;
-
- // Note that to get the return type we have to use
- // TREE_TYPE(TREE_TYPE()) and not DECL_RESULT, as
- // suggested in the documentation.
- //
- tree r (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (f))));
- int tc (TREE_CODE (r));
-
- // In the strict mode make sure the function returns for non-array
- // types a value or a (const) reference to the member type and for
- // array types a (const) pointer to element type. In the lax mode
- // we just check that the return value is not void.
- //
- if (strict)
- {
- semantics::type& t (utype (m));
- semantics::array* ar (dynamic_cast<semantics::array*> (&t));
-
- if (ar != 0 && tc != POINTER_TYPE)
- return found_none;
-
- tree bt (ar != 0 || tc == REFERENCE_TYPE ? TREE_TYPE (r) : r);
- tree bt_mv (TYPE_MAIN_VARIANT (bt));
-
- if ((ar != 0 ? ar->base_type () : t).tree_node () != bt_mv)
- return found_none;
- }
- else if (r == void_type_node)
- return found_none;
-
- cxx_tokens& e (ma.expr);
- e.push_back (cxx_token (0, CPP_KEYWORD, "this"));
- e.push_back (cxx_token (0, CPP_DOT));
- e.push_back (cxx_token (0, CPP_NAME, n));
- e.push_back (cxx_token (0, CPP_OPEN_PAREN, n));
- e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n));
-
- // See if it returns by value.
- //
- ma.by_value = (tc != REFERENCE_TYPE && tc != POINTER_TYPE);
-
- return found_best;
- }
-
- // Check if a function is a suitable modifier for this member.
- //
- found_type
- check_modifier (semantics::data_member& m,
- tree f,
- string const& n,
- member_access& ma,
- bool strict)
- {
- tree a (DECL_ARGUMENTS (f));
- a = DECL_CHAIN (a); // Skip this.
-
- // For a modifier, it can either be a function that returns a non-
- // const reference (or non-const pointer, in case the member is an
- // array) or a by-value modifier that sets a new value. If both are
- // available, we prefer the former for efficiency.
- //
- cxx_tokens& e (ma.expr);
- semantics::type& t (utype (m));
- semantics::array* ar (dynamic_cast<semantics::array*> (&t));
-
- if (a == NULL_TREE)
+ if (m.count ("polymorphic-ref"))
{
- // Note that to get the return type we have to use
- // TREE_TYPE(TREE_TYPE()) and not DECL_RESULT, as
- // suggested in the documentation.
- //
- tree r (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (f))));
- int tc (TREE_CODE (r));
-
- // By-reference modifier. Should return a reference or a pointer.
- //
- if (tc != (ar != 0 ? POINTER_TYPE : REFERENCE_TYPE))
- return found_none;
-
- // The base type should not be const and, in strict mode, should
- // match the member type.
- //
- tree bt (TREE_TYPE (r));
-
- if (CP_TYPE_CONST_P (bt))
- return found_none;
-
- tree bt_mv (TYPE_MAIN_VARIANT (bt));
-
- if (strict && (ar != 0 ? ar->base_type () : t).tree_node () != bt_mv)
- return found_none;
-
- e.clear (); // Could contain by value modifier.
- e.push_back (cxx_token (0, CPP_KEYWORD, "this"));
- e.push_back (cxx_token (0, CPP_DOT));
- e.push_back (cxx_token (0, CPP_NAME, n));
- e.push_back (cxx_token (0, CPP_OPEN_PAREN, n));
- e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n));
-
- return found_best;
+ m.set ("not-null", true);
+ m.set ("deferred", false);
+ m.set ("on-delete", sema_rel::foreign_key::cascade);
}
- // Otherwise look for a by value modifier, which is a function
- // with a single argument.
- //
- else if (DECL_CHAIN (a) == NULL_TREE)
- {
- // In the lax mode any function with a single argument works
- // for us. And we don't care what it returns.
- //
- if (strict)
- {
- // In the strict mode make sure the argument matches the
- // member. This is exactly the same logic as in accessor
- // with regards to arrays, references, etc.
- //
- tree at (TREE_TYPE (a));
- int tc (TREE_CODE (at));
-
- if (ar != 0 && tc != POINTER_TYPE)
- return found_none;
-
- tree bt (ar != 0 || tc == REFERENCE_TYPE ? TREE_TYPE (at) : at);
- tree bt_mv (TYPE_MAIN_VARIANT (bt));
-
- if ((ar != 0 ? ar->base_type () : t).tree_node () != bt_mv)
- return found_none;
- }
-
- if (e.empty ())
- {
- e.push_back (cxx_token (0, CPP_KEYWORD, "this"));
- e.push_back (cxx_token (0, CPP_DOT));
- e.push_back (cxx_token (0, CPP_NAME, n));
- e.push_back (cxx_token (0, CPP_OPEN_PAREN, n));
- e.push_back (cxx_token (0, CPP_QUERY));
- e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n));
-
- // Continue searching in case there is version that returns a
- // non-const reference which we prefer for efficiency.
- //
- return found_some;
- }
- else
- return found_none; // We didn't find anything better.
- }
-
- return found_none;
- }
-
- void
- process_access (semantics::data_member& m, std::string const& k)
- {
- bool virt (m.count ("virtual"));
-
- // Ignore certain special virtual members.
- //
- if (virt && (m.count ("polymorphic-ref") || m.count ("discriminator")))
- return;
-
- char const* kind (k == "get" ? "accessor" : "modifier");
- semantics::class_& c (dynamic_cast<semantics::class_&> (m.scope ()));
-
- // If we don't have an access expression, try to come up with
- // one.
- //
- if (!m.count (k))
- {
- found_type found (found_none);
- semantics::access const& a (m.named ().access ());
- member_access& ma (m.set (k, member_access (m.location (), true)));
-
- // If this member is not virtual and is either public or if we
- // are a friend of this class, then go for the member directly.
- //
- if (!virt && (a == semantics::access::public_ ||
- c.get<bool> ("friend")))
- {
- ma.expr.push_back (cxx_token (0, CPP_KEYWORD, "this"));
- ma.expr.push_back (cxx_token (0, CPP_DOT));
- ma.expr.push_back (cxx_token (0, CPP_NAME, m.name ()));
- found = found_best;
- }
-
- // Otherwise, try to find a suitable accessor/modifier.
- //
-
- // First try the original name. If that doesn't produce anything,
- // then try the public name.
- //
- bool t (k == "get"
- ? options.accessor_regex_trace ()
- : options.modifier_regex_trace ());
- regex_mapping const& re (
- k == "get" ? accessor_regex : modifier_regex);
-
- for (unsigned short j (0); found != found_best && j != 2; ++j)
- {
- string b (j == 0 ? m.name () : public_name (m, false));
-
- // Skip the second pass if original and public names are the same.
- //
- if (j == 1 && b == m.name ())
- continue;
-
- if (t)
- cerr << kind << (j == 0 ? " original" : " public")
- << " name '" << b << "'" << endl;
-
- for (regex_mapping::const_iterator i (re.begin ());
- found != found_best && i != re.end ();
- ++i)
- {
- if (t)
- cerr << "try: '" << i->regex () << "' : ";
-
- if (!i->match (b))
- {
- if (t)
- cerr << '-' << endl;
- continue;
- }
-
- string n (i->replace (b));
-
- if (t)
- cerr << "'" << n << "' : ";
-
- tree decl (
- lookup_qualified_name (
- c.tree_node (), get_identifier (n.c_str ()), false, false));
-
- if (decl == error_mark_node || TREE_CODE (decl) != BASELINK)
- {
- if (t)
- cerr << '-' << endl;
- continue;
- }
-
- // OVL_* macros work for both FUNCTION_DECL and OVERLOAD.
- //
- for (tree o (BASELINK_FUNCTIONS (decl));
- o != 0;
- o = OVL_NEXT (o))
- {
- tree f (OVL_CURRENT (o));
-
- // We are only interested in public non-static member
- // functions. Note that TREE_PUBLIC() returns something
- // other than what we need.
- //
- if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (f) ||
- TREE_PRIVATE (f) || TREE_PROTECTED (f))
- continue;
-
- found_type r (k == "get"
- ? check_accessor (m, f, n, ma, true)
- : check_modifier (m, f, n, ma, true));
-
- if (r != found_none)
- {
- // Update the location of the access expression to point
- // to this function.
- //
- ma.loc = location (DECL_SOURCE_LOCATION (f));
- found = r;
- }
- }
-
- if (t)
- cerr << (found != found_none ? '+' : '-') << endl;
- }
- }
-
- // If that didn't work then the generated code won't be able
- // to access this member.
- //
- if (found == found_none)
- {
- location const& l (m.location ());
-
- if (virt)
- {
- error (l) << "no suitable " << kind << " function could be "
- << "automatically found for virtual data member '"
- << m.name () << "'" << endl;
-
- info (l) << "use '#pragma db " << k << "' to explicitly "
- << "specify the " << kind << " function or "
- << "expression" << endl;
- }
- else
- {
- error (l) << "data member '" << m.name () << "' is "
- << a.string () << " and no suitable " << kind
- << " function could be automatically found" << endl;
- info (l) << "consider making class 'odb::access' a friend of "
- << "class '" << class_name (c) << "'" << endl;
-
- info (l) << "or use '#pragma db " << k << "' to explicitly "
- << "specify the " << kind << " function or "
- << "expression" << endl;
- }
-
- throw operation_failed ();
- }
- }
-
- member_access& ma (m.get<member_access> (k));
- cxx_tokens& e (ma.expr);
-
- // If it is just a name, resolve it and convert to an appropriate
- // expression.
- //
- if (e.size () == 1 && e.back ().type == CPP_NAME)
- {
- string n (e.back ().literal);
- e.clear ();
-
- tree decl (
- lookup_qualified_name (
- c.tree_node (), get_identifier (n.c_str ()), false, false));
-
- if (decl == error_mark_node)
- {
- error (ma.loc) << "unable to resolve data member or function "
- << "name '" << n << "'" << endl;
- throw operation_failed ();
- }
-
- switch (TREE_CODE (decl))
- {
- case FIELD_DECL:
- {
- e.push_back (cxx_token (0, CPP_KEYWORD, "this"));
- e.push_back (cxx_token (0, CPP_DOT));
- e.push_back (cxx_token (0, CPP_NAME, n));
- break;
- }
- case BASELINK:
- {
- // OVL_* macros work for both FUNCTION_DECL and OVERLOAD.
- //
- for (tree o (BASELINK_FUNCTIONS (decl));
- o != 0;
- o = OVL_NEXT (o))
- {
- tree f (OVL_CURRENT (o));
-
- // We are only interested in non-static member functions.
- //
- if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (f))
- continue;
-
- if ((k == "get"
- ? check_accessor (m, f, n, ma, false)
- : check_modifier (m, f, n, ma, false)) == found_best)
- break;
- }
-
- if (e.empty ())
- {
- error (ma.loc) << "unable to find suitable " << kind
- << " function '" << n << "'" << endl;
- throw operation_failed ();
- }
- break;
- }
- default:
- {
- error (ma.loc) << "name '" << n << "' does not refer to a data "
- << "member or function" << endl;
- throw operation_failed ();
- }
- }
- }
-
- // If there is no 'this' keyword, then add it as a prefix.
- //
- {
- bool t (false);
- for (cxx_tokens::iterator i (e.begin ()); i != e.end (); ++i)
- {
- if (i->type == CPP_KEYWORD && i->literal == "this")
- {
- t = true;
- break;
- }
- }
-
- if (!t)
- {
- e.insert (e.begin (), cxx_token (0, CPP_DOT));
- e.insert (e.begin (), cxx_token (0, CPP_KEYWORD, "this"));
- }
- }
-
- // Check that there is no placeholder in the accessor expression.
- //
- if (k == "get" && ma.placeholder ())
- {
- error (ma.loc) << "(?) placeholder in the accessor expression"
- << endl;
- throw operation_failed ();
- }
-
- // Check that the member type is default-constructible if we
- // have a by value modifier.
- //
- if (k == "set" && ma.placeholder ())
- {
- semantics::class_* c (dynamic_cast<semantics::class_*> (&utype (m)));
-
- // Assume all other types are default-constructible.
- //
- if (c != 0)
- {
- // If this type is a class template instantiation, then make
- // sure it is instantiated. While types used in real members
- // will be instantiated, this is not necessarily the case for
- // virtual members. Without the instantiation we won't be able
- // to detect whether the type has the default ctor.
- //
- // It would have been cleaner to do it in post_process_pragmas()
- // but there we don't yet know whether we need the default ctor.
- // And it is a good idea not to require instantiability unless
- // we really need it.
- //
- tree type (c->tree_node ());
-
- if (!COMPLETE_TYPE_P (type) &&
- CLASSTYPE_TEMPLATE_INSTANTIATION (type))
- {
- // Reset input location so that we get nice diagnostics in
- // case of an error. Use the location of the virtual pragma.
- //
- location_t loc (m.get<location_t> ("virtual-location"));
- input_location = loc;
-
- if (instantiate_class_template (type) == error_mark_node ||
- errorcount != 0 ||
- !COMPLETE_TYPE_P (type))
- {
- error (loc) << "unable to instantiate virtual data member " <<
- "type" << endl;
- throw operation_failed ();
- }
- }
-
- if (!c->default_ctor ())
- {
- error (ma.loc) << "modifier expression requires member type " <<
- "to be default-constructible" << endl;
- throw operation_failed ();
- }
- }
- }
+ process_index (m);
}
// Convert index/unique specifiers to the index entry in the object.
@@ -2351,44 +1868,7 @@ namespace relational
struct class_: traversal::class_, context
{
class_ ()
- : std_string_ (0), std_string_hint_ (0), access_ (0)
{
- // Resolve the std::string type node.
- //
- using semantics::scope;
-
- for (scope::names_iterator_pair ip (unit.find ("std"));
- ip.first != ip.second; ++ip.first)
- {
- if (scope* ns = dynamic_cast<scope*> (&ip.first->named ()))
- {
- scope::names_iterator_pair jp (ns->find ("string"));
-
- if (jp.first != jp.second)
- {
- std_string_ = dynamic_cast<semantics::type*> (
- &jp.first->named ());
- std_string_hint_ = &*jp.first;
- break;
- }
- }
- }
-
- assert (std_string_ != 0); // No std::string?
-
- // Resolve odb::access, if any.
- //
- tree odb = lookup_qualified_name (
- global_namespace, get_identifier ("odb"), false, false);
-
- if (odb != error_mark_node)
- {
- access_ = lookup_qualified_name (
- odb, get_identifier ("access"), true, false);
-
- access_ = (access_ != error_mark_node ? TREE_TYPE (access_) : 0);
- }
-
*this >> member_names_ >> member_;
}
@@ -2400,28 +1880,12 @@ namespace relational
if (k == class_other)
return;
- // Check if odb::access is a friend of this class.
- //
- c.set ("friend", access_ != 0 && is_friend (c.tree_node (), access_));
-
- // Assign pointer.
- //
- if (k == class_object || k == class_view)
- assign_pointer (c);
-
- // Do some additional pre-processing.
- //
- if (k == class_object)
- traverse_object_pre (c);
-
names (c);
- // Do some additional post-processing.
- //
if (k == class_object)
- traverse_object_post (c);
+ traverse_object (c);
else if (k == class_view)
- traverse_view_post (c);
+ traverse_view (c);
}
//
@@ -2429,149 +1893,7 @@ namespace relational
//
virtual void
- traverse_object_pre (type& c)
- {
- semantics::class_* poly_root (polymorphic (c));
-
- // Determine whether it is a session object.
- //
- if (!c.count ("session"))
- {
- // If this is a derived class in a polymorphic hierarchy,
- // then it should have the same session value as the root.
- //
- if (poly_root != 0 && poly_root != &c)
- c.set ("session", session (*poly_root));
- else
- {
- // See if any of the namespaces containing this class specify
- // the session value.
- //
- bool found (false);
- for (semantics::scope* s (&c.scope ());; s = &s->scope_ ())
- {
- using semantics::namespace_;
-
- namespace_* ns (dynamic_cast<namespace_*> (s));
-
- if (ns == 0)
- continue; // Some other scope.
-
- if (ns->extension ())
- ns = &ns->original ();
-
- if (ns->count ("session"))
- {
- c.set ("session", ns->get<bool> ("session"));
- found = true;
- break;
- }
-
- if (ns->global_scope ())
- break;
- }
-
- // If still not found, then use the default value.
- //
- if (!found)
- c.set ("session", options.generate_session ());
- }
- }
-
- if (session (c))
- features.session_object = true;
-
- if (poly_root != 0)
- {
- using namespace semantics;
-
- semantics::data_member& idm (*id_member (*poly_root));
-
- if (poly_root != &c)
- {
- // If we are a derived class in the polymorphic persistent
- // class hierarchy, then add a synthesized virtual pointer
- // member that points back to the root.
- //
- path const& f (idm.file ());
- size_t l (idm.line ()), col (idm.column ());
-
- semantics::data_member& m (
- unit.new_node<semantics::data_member> (f, l, col, tree (0)));
- m.set ("virtual", true);
-
- // Make it the first member in the class.
- //
- node_position<type, scope::names_iterator> np (c, c.names_end ());
- unit.new_edge<semantics::names> (
- np, m, idm.name (), access::public_);
-
- // Use the raw pointer as this member's type.
- //
- if (!poly_root->pointed_p ())
- {
- // Create the pointer type in the graph. The pointer node
- // in GCC seems to always be present, even if not explicitly
- // used in the translation unit.
- //
- tree t (poly_root->tree_node ());
- tree ptr (TYPE_POINTER_TO (t));
- assert (ptr != 0);
- ptr = TYPE_MAIN_VARIANT (ptr);
- pointer& p (unit.new_node<pointer> (f, l, col, ptr));
- unit.insert (ptr, p);
- unit.new_edge<points> (p, *poly_root);
- assert (poly_root->pointed_p ());
- }
-
- unit.new_edge<belongs> (m, poly_root->pointed ().pointer ());
-
- m.set ("not-null", true);
- m.set ("deferred", false);
- m.set ("on-delete", sema_rel::foreign_key::cascade);
-
- // Mark it as a special kind of id.
- //
- m.set ("id", true);
- m.set ("polymorphic-ref", true);
- }
- else
- {
- // If we are a root of the polymorphic persistent class hierarchy,
- // then add a synthesized virtual member for the discriminator.
- // Use the location of the polymorphic pragma as the location of
- // this member.
- //
- location_t loc (c.get<location_t> ("polymorphic-location"));
- semantics::data_member& m (
- unit.new_node<semantics::data_member> (
- path (LOCATION_FILE (loc)),
- LOCATION_LINE (loc),
- LOCATION_COLUMN (loc),
- tree (0)));
- m.set ("virtual", true);
-
- // Insert it after the id member (or first if this id comes
- // from reuse-base).
- //
- node_position<type, scope::names_iterator> np (
- c, c.find (idm.named ()));
- unit.new_edge<semantics::names> (
- np, m, "typeid_", access::public_);
-
- belongs& edge (unit.new_edge<belongs> (m, *std_string_));
- edge.hint (*std_string_hint_);
-
- m.set ("readonly", true);
- m.set ("discriminator", true);
-
- c.set ("discriminator", &m);
- }
- }
- }
-
- virtual void
- traverse_object_post (type& c)
+ traverse_object (type& c)
{
// Process indexes. Here we need to do two things: resolve member
// names to member paths and assign names to unnamed indexes. We
@@ -2767,7 +2089,7 @@ namespace relational
typedef vector<relationship> relationships;
virtual void
- traverse_view_post (type& c)
+ traverse_view (type& c)
{
bool has_q (c.count ("query"));
bool has_o (c.count ("objects"));
@@ -3154,417 +2476,11 @@ namespace relational
view_object& pointee_;
};
- void
- assign_pointer (type& c)
- {
- location_t loc (0); // Pragma location, or 0 if not used.
-
- try
- {
- string ptr;
- string const& type (class_fq_name (c));
-
- tree decl (0); // Resolved template node.
- string decl_name; // User-provided template name.
- tree resolve_scope (0); // Scope in which we resolve names.
-
- class_pointer const* cp (0);
- bool cp_template (false);
-
- if (c.count ("pointer"))
- {
- cp = &c.get<class_pointer> ("pointer");
- }
- // If we are a derived type in polymorphic hierarchy, then use
- // our root's pointer type by default.
- //
- else if (semantics::class_* r = polymorphic (c))
- {
- if (&c != r && r->count ("pointer-template"))
- cp = r->get<class_pointer const*> ("pointer-template");
- }
-
- if (cp != 0)
- {
- string const& p (cp->name);
-
- if (p == "*")
- {
- ptr = type + "*";
- cp_template = true;
- }
- else if (p[p.size () - 1] == '*')
- ptr = p;
- else if (p.find ('<') != string::npos)
- {
- // Template-id.
- //
- ptr = p;
- decl_name.assign (p, 0, p.find ('<'));
- }
- else
- {
- // This is not a template-id. Resolve it and see if it is a
- // template or a type.
- //
- decl = resolve_name (p, cp->scope, true);
- int tc (TREE_CODE (decl));
-
- if (tc == TYPE_DECL)
- {
- ptr = p;
-
- // This can be a typedef'ed alias for a TR1 template-id.
- //
- if (tree ti = TYPE_TEMPLATE_INFO (TREE_TYPE (decl)))
- {
- decl = TI_TEMPLATE (ti); // DECL_TEMPLATE
-
- // Get to the most general template declaration.
- //
- while (DECL_TEMPLATE_INFO (decl))
- decl = DECL_TI_TEMPLATE (decl);
- }
- else
- decl = 0; // Not a template.
- }
- else if (tc == TEMPLATE_DECL && DECL_CLASS_TEMPLATE_P (decl))
- {
- ptr = p + "< " + type + " >";
- decl_name = p;
- cp_template = true;
- }
- else
- {
- error (cp->loc)
- << "name '" << p << "' specified with db pragma pointer "
- << "does not name a type or a template" << endl;
-
- throw operation_failed ();
- }
- }
-
- // Resolve scope is the scope of the pragma.
- //
- resolve_scope = cp->scope;
- loc = cp->loc;
- }
- else
- {
- // See if any of the namespaces containing this class specify
- // a pointer.
- //
- for (semantics::scope* s (&c.scope ());; s = &s->scope_ ())
- {
- using semantics::namespace_;
-
- namespace_* ns (dynamic_cast<namespace_*> (s));
-
- if (ns == 0)
- continue; // Some other scope.
-
- if (ns->extension ())
- ns = &ns->original ();
-
- if (!ns->count ("pointer"))
- {
- if (ns->global_scope ())
- break;
- else
- continue;
- }
-
- cp = &ns->get<class_pointer> ("pointer");
- string const& p (cp->name);
-
- // Namespace-specified pointer can only be '*' or are template.
- //
- if (p == "*")
- ptr = type + "*";
- else if (p[p.size () - 1] == '*')
- {
- error (cp->loc)
- << "name '" << p << "' specified with db pragma pointer "
- << "at namespace level cannot be a raw pointer" << endl;
- }
- else if (p.find ('<') != string::npos)
- {
- error (cp->loc)
- << "name '" << p << "' specified with db pragma pointer "
- << "at namespace level cannot be a template-id" << endl;
- }
- else
- {
- // Resolve this name and make sure it is a template.
- //
- decl = resolve_name (p, cp->scope, true);
- int tc (TREE_CODE (decl));
-
- if (tc == TEMPLATE_DECL && DECL_CLASS_TEMPLATE_P (decl))
- {
- ptr = p + "< " + type + " >";
- decl_name = p;
- }
- else
- {
- error (cp->loc)
- << "name '" << p << "' specified with db pragma pointer "
- << "does not name a template" << endl;
- }
- }
-
- if (ptr.empty ())
- throw operation_failed ();
-
- cp_template = true;
-
- // Resolve scope is the scope of the pragma.
- //
- resolve_scope = cp->scope;
- loc = cp->loc;
- break;
- }
-
- // Use the default pointer.
- //
- if (ptr.empty ())
- {
- string const& p (options.default_pointer ());
-
- if (p == "*")
- ptr = type + "*";
- else
- {
- ptr = p + "< " + type + " >";
- decl_name = p;
- }
-
- // Resolve scope is the scope of the class.
- //
- resolve_scope = c.scope ().tree_node ();
- }
- }
-
- // If this class is a root of a polymorphic hierarchy, then cache
- // the pointer template so that we can use it for derived classes.
- //
- if (cp != 0 && cp_template && polymorphic (c) == &c)
- c.set ("pointer-template", cp);
-
- // Check if we are using TR1.
- //
- if (decl != 0 || !decl_name.empty ())
- {
- bool& tr1 (features.tr1_pointer);
- bool& boost (features.boost_pointer);
-
- // First check the user-supplied name.
- //
- tr1 = tr1
- || decl_name.compare (0, 8, "std::tr1") == 0
- || decl_name.compare (0, 10, "::std::tr1") == 0;
-
- // If there was no match, also resolve the name since it can be
- // a using-declaration for a TR1 template.
- //
- if (!tr1)
- {
- if (decl == 0)
- decl = resolve_name (decl_name, resolve_scope, false);
-
- if (TREE_CODE (decl) != TEMPLATE_DECL || !
- DECL_CLASS_TEMPLATE_P (decl))
- {
- // This is only checked for the --default-pointer option.
- //
- error (c.file (), c.line (), c.column ())
- << "name '" << decl_name << "' specified with the "
- << "--default-pointer option does not name a class "
- << "template" << endl;
-
- throw operation_failed ();
- }
-
- string n (decl_as_string (decl, TFF_PLAIN_IDENTIFIER));
-
- // In case of a boost TR1 implementation, we cannot distinguish
- // between the boost:: and std::tr1:: usage since the latter is
- // just a using-declaration for the former.
- //
- tr1 = tr1
- || n.compare (0, 8, "std::tr1") == 0
- || n.compare (0, 10, "::std::tr1") == 0;
-
- boost = boost
- || n.compare (0, 17, "boost::shared_ptr") == 0
- || n.compare (0, 19, "::boost::shared_ptr") == 0;
- }
- }
-
- // Fully-qualify all the unqualified components of the name.
- //
- try
- {
- lex_.start (ptr);
- ptr.clear ();
-
- string t;
- bool punc (false);
- bool scoped (false);
-
- for (cpp_ttype tt (lex_.next (t));
- tt != CPP_EOF;
- tt = lex_.next (t))
- {
- if (punc && tt > CPP_LAST_PUNCTUATOR)
- ptr += ' ';
-
- punc = false;
-
- switch (static_cast<unsigned> (tt))
- {
- case CPP_LESS:
- {
- ptr += "< ";
- break;
- }
- case CPP_GREATER:
- {
- ptr += " >";
- break;
- }
- case CPP_COMMA:
- {
- ptr += ", ";
- break;
- }
- case CPP_NAME:
- {
- // If the name was not preceeded with '::', look it
- // up in the pragmas's scope and add the qualifer.
- //
- if (!scoped)
- {
- tree decl (resolve_name (t, resolve_scope, false));
- tree scope (CP_DECL_CONTEXT (decl));
-
- if (scope != global_namespace)
- {
- ptr += "::";
- ptr += decl_as_string (scope, TFF_PLAIN_IDENTIFIER);
- }
-
- ptr += "::";
- }
-
- ptr += t;
- punc = true;
- break;
- }
- case CPP_KEYWORD:
- case CPP_NUMBER:
- {
- ptr += t;
- punc = true;
- break;
- }
- default:
- {
- ptr += t;
- break;
- }
- }
-
- scoped = (tt == CPP_SCOPE);
- }
- }
- catch (cxx_lexer::invalid_input const&)
- {
- throw operation_failed ();
- }
-
- c.set ("object-pointer", ptr);
- }
- catch (invalid_name const& ex)
- {
- if (loc != 0)
- error (loc)
- << "name '" << ex.name () << "' specified with db pragma "
- << "pointer is invalid" << endl;
- else
- error (c.file (), c.line (), c.column ())
- << "name '" << ex.name () << "' specified with the "
- << "--default-pointer option is invalid" << endl;
-
-
- throw operation_failed ();
- }
- catch (unable_to_resolve const& ex)
- {
- if (loc != 0)
- error (loc)
- << "unable to resolve name '" << ex.name () << "' specified "
- << "with db pragma pointer" << endl;
- else
- error (c.file (), c.line (), c.column ())
- << "unable to resolve name '" << ex.name () << "' specified "
- << "with the --default-pointer option" << endl;
-
- throw operation_failed ();
- }
- }
-
- private:
- struct invalid_name
- {
- invalid_name (string const& n): name_ (n) {}
-
- string const&
- name () const {return name_;}
-
- private:
- string name_;
- };
-
- typedef lookup::unable_to_resolve unable_to_resolve;
-
- tree
- resolve_name (string const& qn, tree scope, bool is_type)
- {
- try
- {
- string tl;
- tree tn;
- cpp_ttype tt, ptt;
-
- nlex_.start (qn);
- tt = nlex_.next (tl, &tn);
-
- string name;
- return lookup::resolve_scoped_name (
- nlex_, tt, tl, tn, ptt, scope, name, is_type);
- }
- catch (cxx_lexer::invalid_input const&)
- {
- throw invalid_name (qn);
- }
- catch (lookup::invalid_name const&)
- {
- throw invalid_name (qn);
- }
- }
-
private:
cxx_string_lexer lex_;
- cxx_string_lexer nlex_; // Nested lexer.
data_member member_;
traversal::names member_names_;
-
- semantics::type* std_string_;
- semantics::names* std_string_hint_;
-
- tree access_; // odb::access node.
};
}
diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx
index 4d56655..7516801 100644
--- a/odb/relational/source.cxx
+++ b/odb/relational/source.cxx
@@ -18,8 +18,8 @@ traverse_object (type& c)
using semantics::data_member;
data_member* id (id_member (c));
- bool auto_id (id ? id->count ("auto") : false);
- bool base_id (id ? &id->scope () != &c : false); // Comes from base.
+ bool auto_id (id && auto_ (*id));
+ bool base_id (id && &id->scope () != &c); // Comes from base.
member_access* id_ma (id ? &id->get<member_access> ("get") : 0);
bool has_ptr (has_a (c, test_pointer));
diff --git a/odb/relational/validator.cxx b/odb/relational/validator.cxx
index 1269406..9d14571 100644
--- a/odb/relational/validator.cxx
+++ b/odb/relational/validator.cxx
@@ -21,11 +21,228 @@ namespace relational
// Pass 2.
//
+ struct data_member2: traversal::data_member, context
+ {
+ data_member2 (bool& valid)
+ : valid_ (valid)
+ {
+ }
+
+ virtual void
+ traverse (type& m)
+ {
+ if (transient (m))
+ return;
+
+ if (null (m))
+ {
+ if (semantics::class_* c = composite_wrapper (utype (m)))
+ {
+ if (has_a (*c, test_container))
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: composite member containing containers cannot "
+ << "be null" << endl;
+
+ os << c->file () << ":" << c->line () << ":" << c->column ()
+ << ": info: composite value type is defined here" << endl;
+
+ valid_ = false;
+ }
+ }
+ }
+ }
+
+ bool& valid_;
+ };
+
+ struct object_no_id_members: object_members_base
+ {
+ object_no_id_members (bool& valid)
+ : object_members_base (false, false, true), valid_ (valid), dm_ (0)
+ {
+ }
+
+ 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 (readonly (member_path_, member_scope_))
+ {
+ semantics::data_member& dm (dm_ != 0 ? *dm_ : m);
+
+ 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;
+ }
+ }
+
+ 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 a composite value type that is used as 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 composite member.
+ };
+
+ struct view_members: object_members_base
+ {
+ view_members (bool& valid)
+ : object_members_base (false, false, true), valid_ (valid), dm_ (0)
+ {
+ }
+
+ virtual void
+ traverse_simple (semantics::data_member& m)
+ {
+ if (object_pointer (utype (m)))
+ {
+ semantics::data_member& dm (dm_ != 0 ? *dm_ : m);
+
+ os << 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 () << ":"
+ << ": info: views cannot contain object pointers" << 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: view data member '" << member_prefix_ << m.name ()
+ << "' is a container" << endl;
+
+ os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":"
+ << ": info: views cannot contain containers" << 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 view data member.
+ };
+
struct class2: traversal::class_, context
{
class2 (bool& valid)
- : valid_ (valid)
+ : valid_ (valid),
+ data_member_ (valid),
+ object_no_id_members_ (valid),
+ composite_id_members_ (valid),
+ view_members_ (valid)
{
+ *this >> data_member_names_ >> data_member_;
}
virtual void
@@ -56,6 +273,66 @@ namespace relational
virtual void
traverse_object (type& c)
{
+ semantics::data_member* id (id_member (c));
+
+ if (id != 0)
+ {
+ if (semantics::class_* cm = 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 (*cm);
+
+ 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 (!cm->default_ctor ())
+ {
+ os << cm->file () << ":" << cm->line () << ":" << cm->column ()
+ << ": error: composite value type that is used as object id "
+ << "is not default-constructible" << endl;
+
+ os << cm->file () << ":" << cm->line () << ":" << cm->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;
+ }
+ }
+ }
+ else
+ {
+ if (!abstract (c))
+ {
+ // Make sure we don't have any containers or inverse pointers.
+ //
+ object_no_id_members_.traverse (c);
+ }
+ }
+
+ names (c);
+
// Validate indexes.
//
{
@@ -90,17 +367,30 @@ namespace relational
}
virtual void
- traverse_view (type&)
+ traverse_view (type& c)
{
+ // Make sure we don't have any containers or object pointers.
+ //
+ view_members_.traverse (c);
+
+ names (c);
}
virtual void
- traverse_composite (type&)
+ traverse_composite (type& c)
{
+ names (c);
}
public:
bool& valid_;
+
+ data_member2 data_member_;
+ traversal::names data_member_names_;
+
+ object_no_id_members object_no_id_members_;
+ composite_id_members composite_id_members_;
+ view_members view_members_;
};
}