aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--odb/context.cxx9
-rw-r--r--odb/generator.cxx90
-rw-r--r--odb/header.cxx321
-rw-r--r--odb/include.cxx2
-rw-r--r--odb/inline.cxx220
-rw-r--r--odb/makefile3
-rw-r--r--odb/odb.cxx658
-rw-r--r--odb/option-functions.cxx61
-rw-r--r--odb/option-parsers.hxx89
-rw-r--r--odb/option-types.cxx45
-rw-r--r--odb/option-types.hxx50
-rw-r--r--odb/options.cli30
-rw-r--r--odb/plugin.cxx2
-rw-r--r--odb/processor.cxx1177
-rw-r--r--odb/profile.cxx8
-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
-rw-r--r--odb/validator.cxx429
23 files changed, 2852 insertions, 2203 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
index 099b10b..2350ad1 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -386,8 +386,13 @@ create_context (ostream& os,
{
auto_ptr<context> r;
- switch (ops.database ())
+ switch (ops.database ()[0])
{
+ case database::common:
+ {
+ r.reset (new context (os, unit, ops, f));
+ break;
+ }
case database::mssql:
{
r.reset (new relational::mssql::context (os, unit, ops, f, m));
@@ -436,7 +441,7 @@ context (ostream& os_,
unit (u),
options (ops),
features (f),
- db (options.database ()),
+ db (options.database ()[0]),
keyword_set (data_->keyword_set_),
include_regex (data_->include_regex_),
accessor_regex (data_->accessor_regex_),
diff --git a/odb/generator.cxx b/odb/generator.cxx
index 5500860..d6456d9 100644
--- a/odb/generator.cxx
+++ b/odb/generator.cxx
@@ -78,6 +78,8 @@ generate (options const& ops,
{
try
{
+ database db (ops.database ()[0]);
+
// First create the database model.
//
cutl::shared_ptr<semantics::relational::model> model;
@@ -86,8 +88,12 @@ generate (options const& ops,
{
auto_ptr<context> ctx (create_context (cerr, unit, ops, fts, 0));
- switch (ops.database ())
+ switch (db)
{
+ case database::common:
+ {
+ break; // No schema for common.
+ }
case database::mssql:
case database::mysql:
case database::oracle:
@@ -109,11 +115,11 @@ generate (options const& ops,
fs::auto_removes auto_rm;
- string hxx_name (base + ops.odb_file_suffix () + ops.hxx_suffix ());
- string ixx_name (base + ops.odb_file_suffix () + ops.ixx_suffix ());
- string cxx_name (base + ops.odb_file_suffix () + ops.cxx_suffix ());
- string sch_name (base + ops.schema_file_suffix () + ops.cxx_suffix ());
- string sql_name (base + ops.sql_suffix ());
+ string hxx_name (base + ops.odb_file_suffix ()[db] + ops.hxx_suffix ());
+ string ixx_name (base + ops.odb_file_suffix ()[db] + ops.ixx_suffix ());
+ string cxx_name (base + ops.odb_file_suffix ()[db] + ops.cxx_suffix ());
+ string sch_name (base + ops.schema_file_suffix ()[db] + ops.cxx_suffix ());
+ string sql_name (base + ops.sql_file_suffix ()[db] + ops.sql_suffix ());
path hxx_path (hxx_name);
path ixx_path (ixx_name);
@@ -173,7 +179,7 @@ generate (options const& ops,
//
ofstream cxx;
- if (gen_cxx)
+ if (gen_cxx && db != database::common)
{
cxx.open (cxx_path.string ().c_str (), ios_base::out);
@@ -190,7 +196,8 @@ generate (options const& ops,
//
//
bool gen_sql_schema (ops.generate_schema () &&
- ops.schema_format ().count (schema_format::sql));
+ ops.schema_format ().count (schema_format::sql) &&
+ db != database::common);
ofstream sql;
if (gen_sql_schema)
@@ -209,9 +216,11 @@ generate (options const& ops,
//
//
- bool gen_sep_schema (gen_cxx &&
- ops.generate_schema () &&
- ops.schema_format ().count (schema_format::separate));
+ bool gen_sep_schema (
+ gen_cxx &&
+ ops.generate_schema () &&
+ ops.schema_format ().count (schema_format::separate) &&
+ db != database::common);
ofstream sch;
@@ -235,7 +244,9 @@ generate (options const& ops,
{
hxx << cxx_file_header;
ixx << cxx_file_header;
- cxx << cxx_file_header;
+
+ if (db != database::common)
+ cxx << cxx_file_header;
}
if (gen_sep_schema)
@@ -299,10 +310,8 @@ generate (options const& ops,
for (paths::const_iterator i (inputs.begin ()); i != inputs.end (); ++i)
hxx << "#include " <<
ctx->process_include_path (i->leaf ().string ()) << endl;
-
hxx << endl;
-
{
// We don't want to indent prologues/epilogues.
//
@@ -314,16 +323,31 @@ generate (options const& ops,
if (!ops.at_once ())
include::generate (true);
- header::generate ();
-
- switch (ops.database ())
+ switch (db)
{
+ case database::common:
+ {
+ header::generate ();
+ break;
+ }
case database::mssql:
case database::mysql:
case database::oracle:
case database::pgsql:
case database::sqlite:
{
+ if (ops.multi_database () == multi_database::disabled)
+ header::generate ();
+ else
+ {
+ string n (base +
+ ops.odb_file_suffix ()[database::common] +
+ ops.hxx_suffix ());
+
+ hxx << "#include " << ctx->process_include_path (n) << endl
+ << endl;
+ }
+
relational::header::generate ();
break;
}
@@ -382,16 +406,22 @@ generate (options const& ops,
//
ind_filter ind (ctx->os);
- inline_::generate ();
-
- switch (ops.database ())
+ switch (db)
{
+ case database::common:
+ {
+ inline_::generate ();
+ break;
+ }
case database::mssql:
case database::mysql:
case database::oracle:
case database::pgsql:
case database::sqlite:
{
+ if (ops.multi_database () == multi_database::disabled)
+ inline_::generate ();
+
relational::inline_::generate ();
break;
}
@@ -417,7 +447,7 @@ generate (options const& ops,
// CXX
//
- if (gen_cxx)
+ if (gen_cxx && db != database::common)
{
auto_ptr<context> ctx (
create_context (cxx, unit, ops, fts, model.get ()));
@@ -453,8 +483,12 @@ generate (options const& ops,
if (!ops.at_once ())
include::generate (false);
- switch (ops.database ())
+ switch (db)
{
+ case database::common:
+ {
+ assert (false);
+ }
case database::mssql:
case database::mysql:
case database::oracle:
@@ -520,8 +554,12 @@ generate (options const& ops,
//
ind_filter ind (ctx->os);
- switch (ops.database ())
+ switch (db)
{
+ case database::common:
+ {
+ assert (false);
+ }
case database::mssql:
case database::mysql:
case database::oracle:
@@ -562,8 +600,12 @@ generate (options const& ops,
auto_ptr<context> ctx (
create_context (sql, unit, ops, fts, model.get ()));
- switch (ops.database ())
+ switch (db)
{
+ case database::common:
+ {
+ assert (false);
+ }
case database::mssql:
case database::mysql:
case database::oracle:
diff --git a/odb/header.cxx b/odb/header.cxx
index 8e39b75..67e4cc0 100644
--- a/odb/header.cxx
+++ b/odb/header.cxx
@@ -10,6 +10,297 @@ using namespace std;
namespace header
{
+ struct class_: traversal::class_, virtual context
+ {
+ virtual void
+ traverse (type& c)
+ {
+ if (!options.at_once () && class_file (c) != unit.file ())
+ return;
+
+ if (object (c))
+ traverse_object (c);
+ else if (view (c))
+ traverse_view (c);
+ }
+
+ void
+ traverse_object (type&);
+
+ void
+ traverse_view (type&);
+
+ void
+ traverse_composite (type&);
+ };
+}
+
+void header::class_::
+traverse_object (type& c)
+{
+ using semantics::data_member;
+
+ data_member* id (id_member (c));
+ bool auto_id (id && auto_ (*id));
+ bool base_id (id && &id->scope () != &c); // Comes from base.
+
+ data_member* optimistic (context::optimistic (c));
+
+ type* poly_root (polymorphic (c));
+ bool poly (poly_root != 0);
+ bool poly_derived (poly && poly_root != &c);
+ type* poly_base (poly_derived ? &polymorphic_base (c) : 0);
+ data_member* discriminator (poly ? context::discriminator (*poly_root) : 0);
+
+ bool abst (abstract (c));
+ bool reuse_abst (abst && !poly);
+
+ string const& type (class_fq_name (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;
+ }
+ }
+
+ // callback ()
+ //
+ os << "static void" << endl
+ << "callback (database&, object_type&, callback_event);"
+ << endl;
+
+ os << "static void" << endl
+ << "callback (database&, const object_type&, callback_event);"
+ << endl;
+ }
+
+ os << "};";
+}
+
+void header::class_::
+traverse_view (type& c)
+{
+ string const& type (class_fq_name (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;"
+ << endl;
+
+ // callback ()
+ //
+ os << "static void" << endl
+ << "callback (database&, view_type&, callback_event);"
+ << endl;
+
+ os << "};";
+}
+
+namespace header
+{
void
generate ()
{
@@ -78,6 +369,34 @@ namespace header
os << "#include <odb/view-result.hxx>" << endl;
}
- os << endl;
+ os << endl
+ << "#include <odb/details/unused.hxx>" << endl
+ << endl;
+
+ // Generate common code.
+ //
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ typedefs unit_typedefs (false);
+ traversal::namespace_ ns;
+ class_ c;
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+ unit >> unit_typedefs >> c;
+
+ traversal::defines ns_defines;
+ typedefs ns_typedefs (false);
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+ ns >> ns_typedefs >> c;
+
+ os << "namespace odb"
+ << "{";
+
+ unit.dispatch (ctx.unit);
+
+ os << "}";
}
}
diff --git a/odb/include.cxx b/odb/include.cxx
index 3d17b9a..c842010 100644
--- a/odb/include.cxx
+++ b/odb/include.cxx
@@ -688,7 +688,7 @@ namespace include
}
path f (inc->path_.base ());
- f += ctx.options.odb_file_suffix ();
+ f += ctx.options.odb_file_suffix ()[ctx.options.database ()[0]];
f += ctx.options.hxx_suffix ();
char o (inc->type_ == include_directive::quote ? '"' : '<');
diff --git a/odb/inline.cxx b/odb/inline.cxx
index e39f85d..39bde4d 100644
--- a/odb/inline.cxx
+++ b/odb/inline.cxx
@@ -5,13 +5,233 @@
#include <odb/common.hxx>
#include <odb/context.hxx>
#include <odb/generate.hxx>
+#include <odb/diagnostics.hxx>
using namespace std;
namespace inline_
{
+ //
+ //
+ struct callback_calls: traversal::class_, virtual context
+ {
+ callback_calls ()
+ {
+ *this >> inherits_ >> *this;
+ }
+
+ 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. Note also that we cannot use
+ // object_type/view_type alias because it can be a base type.
+ //
+ 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_;
+ };
+
+ struct class_: traversal::class_, virtual context
+ {
+ virtual void
+ traverse (type& c)
+ {
+ if (!options.at_once () && class_file (c) != unit.file ())
+ return;
+
+ if (object (c))
+ traverse_object (c);
+ else if (view (c))
+ traverse_view (c);
+ }
+
+ void
+ traverse_object (type&);
+
+ void
+ traverse_view (type&);
+
+ private:
+ callback_calls callback_calls_;
+ };
+}
+
+void inline_::class_::
+traverse_object (type& c)
+{
+ using semantics::data_member;
+
+ data_member* id (id_member (c));
+ bool base_id (id && &id->scope () != &c); // Comes from base.
+
+ // Base class that contains the object id.
+ //
+ type* base (id != 0 && base_id ? dynamic_cast<type*> (&id->scope ()) : 0);
+
+ bool poly (polymorphic (c));
+ bool abst (abstract (c));
+ bool reuse_abst (abst && !poly);
+
+ string const& type (class_fq_name (c));
+ string traits ("access::object_traits< " + type + " >");
+
+ 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 << "}";
+ }
+
+ // The rest does not apply to reuse-abstract objects.
+ //
+ if (reuse_abst)
+ return;
+
+ // callback ()
+ //
+ os << "inline" << endl
+ << "void " << traits << "::" << 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 << "::" << 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 << "}";
+}
+
+void inline_::class_::
+traverse_view (type& c)
+{
+ string const& type (class_fq_name (c));
+ string traits ("access::view_traits< " + type + " >");
+
+ os << "// " << class_name (c) << endl
+ << "//" << endl
+ << endl;
+
+ // 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 << "}";
+}
+
+namespace inline_
+{
void
generate ()
{
+ context ctx;
+ ostream& os (ctx.os);
+
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ typedefs unit_typedefs (false);
+ traversal::namespace_ ns;
+ class_ c;
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+ unit >> unit_typedefs >> c;
+
+ traversal::defines ns_defines;
+ typedefs ns_typedefs (false);
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+ ns >> ns_typedefs >> c;
+
+ os << "namespace odb"
+ << "{";
+
+ unit.dispatch (ctx.unit);
+
+ os << "}";
}
}
diff --git a/odb/makefile b/odb/makefile
index c57ed9f..bb0deba 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -200,7 +200,8 @@ $(gen): cli_options += \
--generate-file-scanner \
--include-with-brackets \
--include-prefix odb \
---guard-prefix ODB
+--guard-prefix ODB \
+--cxx-prologue '\#include <odb/option-parsers.hxx>'
$(call include-dep,$(cxx_pod) $(cxx_dod) $(cxx_cod),\
$(cxx_pobj) $(cxx_dobj) $(cxx_cobj),$(gen))
diff --git a/odb/odb.cxx b/odb/odb.cxx
index e18feeb..b80f577 100644
--- a/odb/odb.cxx
+++ b/odb/odb.cxx
@@ -123,6 +123,7 @@ profile_paths (strings const& args, char const* name);
static char const* const db_macro[] =
{
+ "-DODB_DATABASE_COMMON",
"-DODB_DATABASE_MSSQL",
"-DODB_DATABASE_MYSQL",
"-DODB_DATABASE_ORACLE",
@@ -491,7 +492,9 @@ main (int argc, char* argv[])
oi[1].option = "-p";
oi[2].option = "--profile";
- database db;
+ vector<database> dbs;
+ bool show_sloc;
+ size_t sloc_limit;
{
oi[1].search_func = &profile_search_ignore;
oi[2].search_func = &profile_search_ignore;
@@ -527,14 +530,24 @@ main (int argc, char* argv[])
// Check that required options were specifed.
//
- if (!ops.database_specified ())
+ dbs = ops.database ();
+
+ if (dbs.empty ())
{
e << argv[0] << ": error: no database specified with the --database "
<< "option" << endl;
return 1;
}
- db = ops.database ();
+ if (dbs.size () > 1 && !ops.multi_database_specified ())
+ {
+ e << argv[0] << ": error: --multi-database option required when " <<
+ "multiple databases are specified"<< endl;
+ return 1;
+ }
+
+ show_sloc = ops.show_sloc ();
+ sloc_limit = ops.sloc_limit_specified () ? ops.sloc_limit () : 0;
// Translate some ODB options to GCC options.
//
@@ -566,26 +579,15 @@ main (int argc, char* argv[])
e << " " << *i << endl;
}
- // Second parse.
+ // Pass profile search paths (svc-path option).
//
- profile_data pd (prof_paths, db, argv[0]);
- oi[1].search_func = &profile_search;
- oi[2].search_func = &profile_search;
- oi[1].arg = &pd;
- oi[2].arg = &pd;
-
- cli::argv_file_scanner scan (ac, &av[0], oi, 3);
- options ops (scan);
-
- size_t end (scan.end () - 1); // We have one less in plugin_args.
-
- if (end == plugin_args.size ())
+ for (paths::const_iterator i (prof_paths.begin ());
+ i != prof_paths.end (); ++i)
{
- e << argv[0] << ": error: input file expected" << endl;
- return 1;
+ args.push_back (encode_plugin_option ("svc-path", i->string ()));
}
- // Add ODB macros.
+ // Add common ODB macros.
//
args.push_back ("-DODB_COMPILER");
@@ -595,396 +597,428 @@ main (int argc, char* argv[])
args.push_back ("-DODB_COMPILER_VERSION=" + ostr.str ());
}
- args.push_back (db_macro[ops.database ()]);
-
- // Encode plugin options.
+ // Compile for each database.
//
- cli::options const& desc (options::description ());
- for (size_t i (0); i < end; ++i)
+ size_t sloc_total (0);
+
+ for (vector<database>::iterator i (dbs.begin ()); i != dbs.end (); ++i)
{
- string k, v;
- string a (plugin_args[i]);
+ database db (*i);
+ strings db_args (args);
- // Ignore certain options.
+ // Add database-specific ODB macro.
//
- if (a == "--")
- {
- // Ignore the option seperator since GCC doesn't understand it.
- //
- continue;
- }
- else if (a == "--std")
- {
- // Translated to GCC -std=.
- //
- ++i;
- continue;
- }
+ db_args.push_back (db_macro[db]);
+
+ // Second parse.
+ //
+ profile_data pd (prof_paths, db, argv[0]);
+ oi[1].search_func = &profile_search;
+ oi[2].search_func = &profile_search;
+ oi[1].arg = &pd;
+ oi[2].arg = &pd;
- cli::options::const_iterator it (desc.find (a));
+ cli::argv_file_scanner scan (ac, &av[0], oi, 3);
+ options ops (scan);
- if (it == desc.end ())
+ size_t end (scan.end () - 1); // We have one less in plugin_args.
+
+ if (end == plugin_args.size ())
{
- e << argv[0] << ": ice: unexpected option '" << a << "'" << endl;
+ e << argv[0] << ": error: input file expected" << endl;
return 1;
}
- if (a.size () > 2 && a[0] == '-' && a[1] == '-')
- k = string (a, 2); // long format
- else
- k = string (a, 1); // short format
-
- // If there are more arguments then we may have a value.
+ // Encode plugin options.
//
- if (!it->flag ())
+ cli::options const& desc (options::description ());
+ for (size_t i (0); i < end; ++i)
{
- if (i + 1 == end)
+ string k, v;
+ string a (plugin_args[i]);
+
+ // Ignore certain options.
+ //
+ if (a == "--")
{
- e << argv[0] << ": ice: expected argument for '" << a << "'" << endl;
- return 1;
+ // Ignore the option seperator since GCC doesn't understand it.
+ //
+ continue;
+ }
+ else if (a == "--std")
+ {
+ // Translated to GCC -std=.
+ //
+ ++i;
+ continue;
+ }
+ else if (a == "-d" || a == "--databse")
+ {
+ // Ignore all other databases.
+ //
+ if (plugin_args[i + 1] != db.string ())
+ {
+ ++i;
+ continue;
+ }
}
- v = plugin_args[++i];
- }
-
- args.push_back (encode_plugin_option (k, v));
- }
-
- // Pass profile search paths (svc-path option).
- //
- for (paths::const_iterator i (prof_paths.begin ());
- i != prof_paths.end (); ++i)
- {
- args.push_back (encode_plugin_option ("svc-path", i->string ()));
- }
-
- // Reserve space for and remember the position of the svc-file
- // option.
- //
- size_t svc_file_pos (args.size ());
- args.push_back ("");
-
- // If compiling multiple input files at once, pass them also with
- // the --svc-file option.
- //
- bool at_once (ops.at_once () && plugin_args.size () - end > 1);
- if (at_once)
- {
- if (ops.output_name ().empty ())
- {
- e << "error: --output-name required when compiling multiple " <<
- "input files at once (--at-once)" << endl;
- return 1;
- }
-
- for (size_t i (end); i < plugin_args.size (); ++i)
- args.push_back (encode_plugin_option ("svc-file", plugin_args[i]));
- }
+ cli::options::const_iterator it (desc.find (a));
- // Create an execvp-compatible argument array.
- //
- typedef vector<char const*> cstrings;
- cstrings exec_args;
+ if (it == desc.end ())
+ {
+ e << argv[0] << ": ice: unexpected option '" << a << "'" << endl;
+ return 1;
+ }
- for (strings::const_iterator i (args.begin ()), end (args.end ());
- i != end; ++i)
- {
- exec_args.push_back (i->c_str ());
- }
+ if (a.size () > 2 && a[0] == '-' && a[1] == '-')
+ k = string (a, 2); // long format
+ else
+ k = string (a, 1); // short format
- exec_args.push_back ("-"); // Compile stdin.
- exec_args.push_back (0);
+ // If there are more arguments then we may have a value.
+ //
+ if (!it->flag ())
+ {
+ if (i + 1 == end)
+ {
+ e << argv[0] << ": ice: expected argument for '" << a << "'"
+ << endl;
+ return 1;
+ }
- // Iterate over the input files and compile each of them.
- //
- size_t sloc_total (0);
+ v = plugin_args[++i];
+ }
- for (; end < plugin_args.size (); ++end)
- {
- string name (at_once ? ops.output_name () : plugin_args[end]);
+ db_args.push_back (encode_plugin_option (k, v));
+ }
- // Set the --svc-file option.
+ // Reserve space for and remember the position of the svc-file
+ // option.
//
- args[svc_file_pos] = encode_plugin_option ("svc-file", name);
- exec_args[svc_file_pos] = args[svc_file_pos].c_str ();
+ size_t svc_file_pos (db_args.size ());
+ db_args.push_back ("");
+ // If compiling multiple input files at once, pass them also with
+ // the --svc-file option.
//
- //
- ifstream ifs;
-
- if (!at_once)
+ bool at_once (ops.at_once () && plugin_args.size () - end > 1);
+ if (at_once)
{
- ifs.open (name.c_str (), ios_base::in | ios_base::binary);
-
- if (!ifs.is_open ())
+ if (ops.output_name ().empty ())
{
- e << name << ": error: unable to open in read mode" << endl;
+ e << "error: --output-name required when compiling multiple " <<
+ "input files at once (--at-once)" << endl;
return 1;
}
- }
- if (v)
- {
- e << "Compiling " << name << endl;
- for (cstrings::const_iterator i (exec_args.begin ());
- i != exec_args.end (); ++i)
- {
- if (*i != 0)
- e << *i << (*(i + 1) != 0 ? ' ' : '\n');
- }
+ for (size_t i (end); i < plugin_args.size (); ++i)
+ db_args.push_back (
+ encode_plugin_option ("svc-file", plugin_args[i]));
}
- process_info pi (start_process (&exec_args[0], argv[0], false, true));
+ // Create an execvp-compatible argument array.
+ //
+ typedef vector<char const*> cstrings;
+ cstrings exec_args;
+ for (strings::const_iterator i (db_args.begin ()), end (db_args.end ());
+ i != end; ++i)
{
- __gnu_cxx::stdio_filebuf<char> fb (
- pi.out_fd, ios_base::out | ios_base::binary);
- ostream os (&fb);
+ exec_args.push_back (i->c_str ());
+ }
- if (!ops.trace ())
- {
- // Add the standard prologue.
- //
- os << "#line 1 \"<standard-odb-prologue>\"" << endl;
+ exec_args.push_back ("-"); // Compile stdin.
+ exec_args.push_back (0);
- // Make sure ODB compiler and libodb versions are compatible.
- //
- os << "#include <odb/version.hxx>" << endl
- << endl
- << "#if ODB_VERSION != " << ODB_VERSION << endl
- << "# error incompatible ODB compiler and runtime " <<
- "versions" << endl
- << "#endif" << endl
- << endl;
-
- // Add ODB compiler metaprogramming tests.
- //
- os << "namespace odb" << endl
- << "{" << endl
- << "namespace compiler" << endl
- << "{" << endl;
+ // Iterate over the input files and compile each of them.
+ //
+ for (; end < plugin_args.size (); ++end)
+ {
+ string name (at_once ? ops.output_name () : plugin_args[end]);
- // operator< test, used in validator.
- //
- os << "template <typename T>" << endl
- << "bool" << endl
- << "has_lt_operator (const T& x, const T& y)" << endl
- << "{" << endl
- << "bool r (x < y);" << endl
- << "return r;" << endl
- << "}" << endl;
-
- os << "}" << endl
- << "}" << endl;
- }
+ // Set the --svc-file option.
+ //
+ db_args[svc_file_pos] = encode_plugin_option ("svc-file", name);
+ exec_args[svc_file_pos] = db_args[svc_file_pos].c_str ();
- // Add custom prologue if any.
//
- // NOTE: if you change the format, you also need to update code
- // in include.cxx
//
- strings const& pro (ops.odb_prologue ());
- for (size_t i (0); i < pro.size (); ++i)
- {
- os << "#line 1 \"<odb-prologue-" << i + 1 << ">\"" << endl
- << pro[i]
- << endl;
- }
+ ifstream ifs;
- strings const& prof (ops.odb_prologue_file ());
- for (size_t i (0); i < prof.size (); ++i)
+ if (!at_once)
{
- os << "#line 1 \"<odb-prologue-" << pro.size () + i + 1 << ">\""
- << endl;
-
- ifstream ifs (prof[i].c_str (), ios_base::in | ios_base::binary);
+ ifs.open (name.c_str (), ios_base::in | ios_base::binary);
if (!ifs.is_open ())
{
- e << prof[i] << ": error: unable to open in read mode" << endl;
- fb.close ();
- wait_process (pi, argv[0]);
+ e << name << ": error: unable to open in read mode" << endl;
return 1;
}
+ }
- if (!(os << ifs.rdbuf ()))
+ if (v)
+ {
+ e << "Compiling " << name << endl;
+ for (cstrings::const_iterator i (exec_args.begin ());
+ i != exec_args.end (); ++i)
{
- e << prof[i] << ": error: io failure" << endl;
- fb.close ();
- wait_process (pi, argv[0]);
- return 1;
+ if (*i != 0)
+ e << *i << (*(i + 1) != 0 ? ' ' : '\n');
}
-
- os << endl;
}
- if (at_once)
- {
- // Include all the input files (no need to escape).
- //
- os << "#line 1 \"<command-line>\"" << endl;
+ process_info pi (start_process (&exec_args[0], argv[0], false, true));
- bool b (ops.include_with_brackets ());
- char op (b ? '<' : '"'), cl (b ? '>' : '"');
-
- for (; end < plugin_args.size (); ++end)
- os << "#include " << op << plugin_args[end] << cl << endl;
- }
- else
{
- // Write the synthesized translation unit to stdout.
- //
- os << "#line 1 \"" << escape_path (name) << "\"" << endl;
+ __gnu_cxx::stdio_filebuf<char> fb (
+ pi.out_fd, ios_base::out | ios_base::binary);
+ ostream os (&fb);
- if (!(os << ifs.rdbuf ()))
+ if (!ops.trace ())
{
- e << name << ": error: io failure" << endl;
- fb.close ();
- wait_process (pi, argv[0]);
- return 1;
+ // Add the standard prologue.
+ //
+ os << "#line 1 \"<standard-odb-prologue>\"" << endl;
+
+ // Make sure ODB compiler and libodb versions are compatible.
+ //
+ os << "#include <odb/version.hxx>" << endl
+ << endl
+ << "#if ODB_VERSION != " << ODB_VERSION << endl
+ << "# error incompatible ODB compiler and runtime " <<
+ "versions" << endl
+ << "#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 (const T& x, const T& y)" << endl
+ << "{" << endl
+ << "bool r (x < y);" << endl
+ << "return r;" << endl
+ << "}" << endl;
+
+ os << "}" << endl
+ << "}" << endl;
}
- // Add a new line in case the input file doesn't end with one.
+ // Add custom prologue if any.
//
- os << endl;
- }
+ // NOTE: if you change the format, you also need to update code
+ // in include.cxx
+ //
+ strings const& pro (ops.odb_prologue ());
+ for (size_t i (0); i < pro.size (); ++i)
+ {
+ os << "#line 1 \"<odb-prologue-" << i + 1 << ">\"" << endl
+ << pro[i] << endl;
+ }
- // Add custom epilogue if any.
- //
- // NOTE: if you change the format, you also need to update code
- // in include.cxx
- //
- strings const& epi (ops.odb_epilogue ());
- for (size_t i (0); i < epi.size (); ++i)
- {
- os << "#line 1 \"<odb-epilogue-" << i + 1 << ">\"" << endl
- << epi[i]
- << endl;
- }
+ strings const& prof (ops.odb_prologue_file ());
+ for (size_t i (0); i < prof.size (); ++i)
+ {
+ os << "#line 1 \"<odb-prologue-" << pro.size () + i + 1 << ">\""
+ << endl;
- strings const& epif (ops.odb_epilogue_file ());
- for (size_t i (0); i < epif.size (); ++i)
- {
- os << "#line 1 \"<odb-epilogue-" << epi.size () + i + 1 << ">\""
- << endl;
+ ifstream ifs (prof[i].c_str (), ios_base::in | ios_base::binary);
- ifstream ifs (epif[i].c_str (), ios_base::in | ios_base::binary);
+ if (!ifs.is_open ())
+ {
+ e << prof[i] << ": error: unable to open in read mode" << endl;
+ fb.close ();
+ wait_process (pi, argv[0]);
+ return 1;
+ }
- if (!ifs.is_open ())
- {
- e << epif[i] << ": error: unable to open in read mode" << endl;
- fb.close ();
- wait_process (pi, argv[0]);
- return 1;
+ if (!(os << ifs.rdbuf ()))
+ {
+ e << prof[i] << ": error: io failure" << endl;
+ fb.close ();
+ wait_process (pi, argv[0]);
+ return 1;
+ }
+
+ os << endl;
}
- if (!(os << ifs.rdbuf ()))
+ if (at_once)
{
- e << epif[i] << ": error: io failure" << endl;
- fb.close ();
- wait_process (pi, argv[0]);
- return 1;
+ // Include all the input files (no need to escape).
+ //
+ os << "#line 1 \"<command-line>\"" << endl;
+
+ bool b (ops.include_with_brackets ());
+ char op (b ? '<' : '"'), cl (b ? '>' : '"');
+
+ for (; end < plugin_args.size (); ++end)
+ os << "#include " << op << plugin_args[end] << cl << endl;
}
+ else
+ {
+ // Write the synthesized translation unit to stdout.
+ //
+ os << "#line 1 \"" << escape_path (name) << "\"" << endl;
- os << endl;
- }
+ if (!(os << ifs.rdbuf ()))
+ {
+ e << name << ": error: io failure" << endl;
+ fb.close ();
+ wait_process (pi, argv[0]);
+ return 1;
+ }
- if (!ops.trace ())
- {
- // Add the standard epilogue at the end so that we see all
- // the declarations.
- //
- os << "#line 1 \"<standard-odb-epilogue>\"" << endl;
+ // Add a new line in case the input file doesn't end with one.
+ //
+ os << endl;
+ }
- // Includes for standard smart pointers. The Boost TR1 header
- // may or may not delegate to the GCC implementation. In either
- // case, the necessary declarations will be provided so we don't
- // need to do anything.
+ // Add custom epilogue if any.
//
- os << "#include <memory>" << endl
- << "#ifndef BOOST_TR1_MEMORY_HPP_INCLUDED" << endl
- << "# include <tr1/memory>" << endl
- << "#endif" << endl;
-
- // Standard wrapper traits.
+ // NOTE: if you change the format, you also need to update code
+ // in include.cxx
//
- os << "#include <odb/wrapper-traits.hxx>" << endl
- << "#include <odb/tr1/wrapper-traits.hxx>" << endl;
+ strings const& epi (ops.odb_epilogue ());
+ for (size_t i (0); i < epi.size (); ++i)
+ {
+ os << "#line 1 \"<odb-epilogue-" << i + 1 << ">\"" << endl
+ << epi[i] << endl;
+ }
- // Standard pointer traits.
- //
- os << "#include <odb/pointer-traits.hxx>" << endl
- << "#include <odb/tr1/pointer-traits.hxx>" << endl;
+ strings const& epif (ops.odb_epilogue_file ());
+ for (size_t i (0); i < epif.size (); ++i)
+ {
+ os << "#line 1 \"<odb-epilogue-" << epi.size () + i + 1 << ">\""
+ << endl;
- // Standard container traits.
- //
- os << "#include <odb/container-traits.hxx>" << endl;
- }
- }
+ ifstream ifs (epif[i].c_str (), ios_base::in | ios_base::binary);
- // Filter the output stream looking for communication from the
- // plugin.
- //
- {
- __gnu_cxx::stdio_filebuf<char> fb (pi.in_ofd, ios_base::in);
- istream is (&fb);
+ if (!ifs.is_open ())
+ {
+ e << epif[i] << ": error: unable to open in read mode" << endl;
+ fb.close ();
+ wait_process (pi, argv[0]);
+ return 1;
+ }
- for (bool first (true); !is.eof (); )
- {
- string line;
- getline (is, line);
+ if (!(os << ifs.rdbuf ()))
+ {
+ e << epif[i] << ": error: io failure" << endl;
+ fb.close ();
+ wait_process (pi, argv[0]);
+ return 1;
+ }
- if (is.fail () && !is.eof ())
+ os << endl;
+ }
+
+ if (!ops.trace ())
{
- e << argv[0] << ": error: io failure while parsing output" << endl;
- wait_process (pi, argv[0]);
- return 1;
+ // Add the standard epilogue at the end so that we see all
+ // the declarations.
+ //
+ os << "#line 1 \"<standard-odb-epilogue>\"" << endl;
+
+ // Includes for standard smart pointers. The Boost TR1 header
+ // may or may not delegate to the GCC implementation. In either
+ // case, the necessary declarations will be provided so we don't
+ // need to do anything.
+ //
+ os << "#include <memory>" << endl
+ << "#ifndef BOOST_TR1_MEMORY_HPP_INCLUDED" << endl
+ << "# include <tr1/memory>" << endl
+ << "#endif" << endl;
+
+ // Standard wrapper traits.
+ //
+ os << "#include <odb/wrapper-traits.hxx>" << endl
+ << "#include <odb/tr1/wrapper-traits.hxx>" << endl;
+
+ // Standard pointer traits.
+ //
+ os << "#include <odb/pointer-traits.hxx>" << endl
+ << "#include <odb/tr1/pointer-traits.hxx>" << endl;
+
+ // Standard container traits.
+ //
+ os << "#include <odb/container-traits.hxx>" << endl;
}
+ }
- if (line.compare (0, 9, "odb:sloc:") == 0)
+ // Filter the output stream looking for communication from the
+ // plugin.
+ //
+ {
+ __gnu_cxx::stdio_filebuf<char> fb (pi.in_ofd, ios_base::in);
+ istream is (&fb);
+
+ for (bool first (true); !is.eof (); )
{
- if (ops.show_sloc () || ops.sloc_limit_specified ())
+ string line;
+ getline (is, line);
+
+ if (is.fail () && !is.eof ())
{
- size_t n;
- istringstream is (string (line, 9, string::npos));
+ e << argv[0] << ": error: io failure while parsing output"
+ << endl;
+ wait_process (pi, argv[0]);
+ return 1;
+ }
- if (!(is >> n && is.eof ()))
+ if (line.compare (0, 9, "odb:sloc:") == 0)
+ {
+ if (show_sloc || sloc_limit != 0)
{
- e << argv[0] << ": error: invalid odb:sloc value" << endl;
- wait_process (pi, argv[0]);
- return 1;
+ size_t n;
+ istringstream is (string (line, 9, string::npos));
+
+ if (!(is >> n && is.eof ()))
+ {
+ e << argv[0] << ": error: invalid odb:sloc value" << endl;
+ wait_process (pi, argv[0]);
+ return 1;
+ }
+
+ sloc_total += n;
}
- sloc_total += n;
+ continue;
}
- continue;
- }
-
- if (first)
- first = false;
- else
- cout << endl;
+ if (first)
+ first = false;
+ else
+ cout << endl;
- cout << line;
+ cout << line;
+ }
}
- }
- if (!wait_process (pi, argv[0]))
- return 1;
- }
+ if (!wait_process (pi, argv[0]))
+ return 1;
+ } // End input file loop.
+ } // End database loop.
// Handle SLOC.
//
- if (ops.show_sloc ())
+ if (show_sloc)
e << "total: " << sloc_total << endl;
- if (ops.sloc_limit_specified () && ops.sloc_limit () < sloc_total)
+ if (sloc_limit != 0 && sloc_limit < sloc_total)
{
- e << argv[0] << ": error: SLOC limit of " << ops.sloc_limit ()
- << " lines has been exceeded" << endl;
+ e << argv[0] << ": error: SLOC limit of " << sloc_limit << " lines " <<
+ "has been exceeded" << endl;
- if (!ops.show_sloc ())
+ if (!show_sloc)
e << argv[0] << ": info: use the --show-sloc option to see the "
<< "current total" << endl;
diff --git a/odb/option-functions.cxx b/odb/option-functions.cxx
index 6b7442e..aca4943 100644
--- a/odb/option-functions.cxx
+++ b/odb/option-functions.cxx
@@ -3,6 +3,7 @@
// license : GNU GPL v3; see accompanying LICENSE file
#include <set>
+#include <utility> // std::make_pair()
#include <odb/option-functions.hxx>
@@ -11,6 +12,8 @@ using namespace std;
void
process_options (options& o)
{
+ database db (o.database ()[0]);
+
// If --generate-schema-only was specified, then set --generate-schema
// as well.
//
@@ -23,8 +26,12 @@ process_options (options& o)
{
set<schema_format> f;
- switch (o.database ())
+ switch (db)
{
+ case database::common:
+ {
+ break; // No schema for common.
+ }
case database::mssql:
case database::mysql:
case database::oracle:
@@ -42,4 +49,56 @@ process_options (options& o)
o.schema_format (f);
}
+
+ // Set default --*--file-suffix values.
+ //
+ {
+ database cm (database::common);
+
+ o.odb_file_suffix ().insert (make_pair (cm, string ("-odb")));
+ o.sql_file_suffix ().insert (make_pair (cm, string ("")));
+ o.schema_file_suffix ().insert (make_pair (cm, string ("-schema")));
+ }
+
+ if (o.multi_database () == multi_database::disabled)
+ {
+ o.odb_file_suffix ().insert (make_pair (db, string ("-odb")));
+ o.sql_file_suffix ().insert (make_pair (db, string ("")));
+ o.schema_file_suffix ().insert (make_pair (db, string ("-schema")));
+ }
+ else
+ {
+ o.odb_file_suffix ().insert (
+ make_pair (db, string ("-odb-") + db.string ()));
+ o.sql_file_suffix ().insert (
+ make_pair (db, string ("-") + db.string ()));
+ o.schema_file_suffix ().insert (
+ make_pair (db, string ("-schema-") + db.string ()));
+ }
+
+ // Set default --default-database value.
+ //
+ if (!o.default_database_specified ())
+ {
+ switch (o.multi_database ())
+ {
+ case multi_database::disabled:
+ {
+ o.default_database (db);
+ o.default_database_specified (true);
+ break;
+ }
+ case multi_database::dynamic:
+ {
+ o.default_database (database::common);
+ o.default_database_specified (true);
+ break;
+ }
+ case multi_database::static_:
+ {
+ // No default database unless explicitly specified.
+ break;
+ }
+ }
+ }
}
diff --git a/odb/option-parsers.hxx b/odb/option-parsers.hxx
new file mode 100644
index 0000000..a8fc1f5
--- /dev/null
+++ b/odb/option-parsers.hxx
@@ -0,0 +1,89 @@
+// file : odb/option-parsers.hxx
+// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_OPTION_PARSERS_HXX
+#define ODB_OPTION_PARSERS_HXX
+
+#include <sstream>
+
+#include <odb/option-types.hxx>
+#include <odb/options.hxx>
+
+namespace cli
+{
+ template <typename V>
+ struct parser<database_map<V> >
+ {
+ static void
+ parse (database_map<V>& m, bool& xs, scanner& s)
+ {
+ typedef database_map<V> map;
+
+ xs = true;
+ std::string o (s.next ());
+
+ if (s.more ())
+ {
+ std::string ov (s.next ());
+ std::string::size_type p = ov.find (':');
+
+ if (p != std::string::npos)
+ {
+ std::string kstr (ov, 0, p);
+ std::string vstr (ov, p + 1);
+
+ // See if this prefix resolves to the database name. If not,
+ // assume there is no prefix.
+ //
+ database k;
+ std::istringstream ks (kstr);
+
+ if (ks >> k && ks.eof ())
+ {
+ V v = V ();
+
+ if (!vstr.empty ())
+ {
+ std::istringstream vs (vstr);
+
+ if (!(vs >> v && vs.eof ()))
+ throw invalid_value (o, ov);
+ }
+
+ m[k] = v; // Override any old value.
+ return;
+ }
+ }
+
+ // No database prefix is specified which means it applies to
+ // all the databases.
+ //
+ V v = V ();
+
+ if (!ov.empty ())
+ {
+ std::istringstream vs (ov);
+
+ if (!(vs >> v && vs.eof ()))
+ throw invalid_value (o, ov);
+ }
+
+ // We don't want to override database-specific values, so use
+ // insert().
+ //
+ m.insert (typename map::value_type (database::common, v));
+ m.insert (typename map::value_type (database::mssql, v));
+ m.insert (typename map::value_type (database::mysql, v));
+ m.insert (typename map::value_type (database::oracle, v));
+ m.insert (typename map::value_type (database::pgsql, v));
+ m.insert (typename map::value_type (database::sqlite, v));
+ }
+ else
+ throw missing_value (o);
+ }
+ };
+}
+
+
+#endif // ODB_OPTION_PARSERS_HXX
diff --git a/odb/option-types.cxx b/odb/option-types.cxx
index ceb71db..c52935e 100644
--- a/odb/option-types.cxx
+++ b/odb/option-types.cxx
@@ -52,6 +52,7 @@ operator>> (istream& is, cxx_version& v)
static const char* database_[] =
{
+ "common",
"mssql",
"mysql",
"oracle",
@@ -92,6 +93,50 @@ operator<< (ostream& os, database db)
}
//
+// multi_database
+//
+
+static const char* multi_database_[] =
+{
+ "dynamic",
+ "static",
+ "disabled"
+};
+
+const char* multi_database::
+string () const
+{
+ return multi_database_[v_];
+}
+
+istream&
+operator>> (istream& is, multi_database& db)
+{
+ string s;
+ is >> s;
+
+ if (!is.fail ())
+ {
+ const char** e (
+ multi_database_ + sizeof (multi_database_) / sizeof (char*) - 1);
+ const char** i (lower_bound (multi_database_, e, s));
+
+ if (i != e && *i == s)
+ db = multi_database::value (i - multi_database_);
+ else
+ is.setstate (istream::failbit);
+ }
+
+ return is;
+}
+
+ostream&
+operator<< (ostream& os, multi_database db)
+{
+ return os << db.string ();
+}
+
+//
// schema_format
//
diff --git a/odb/option-types.hxx b/odb/option-types.hxx
index 66e2f28..732cd5a 100644
--- a/odb/option-types.hxx
+++ b/odb/option-types.hxx
@@ -5,7 +5,9 @@
#ifndef ODB_OPTION_TYPES_HXX
#define ODB_OPTION_TYPES_HXX
+#include <map>
#include <iosfwd>
+#include <cassert>
#include <odb/semantics/relational/name.hxx>
@@ -40,6 +42,7 @@ struct database
{
// Keep in alphabetic order.
//
+ common,
mssql,
mysql,
oracle,
@@ -65,6 +68,53 @@ operator<< (std::ostream&, database);
//
//
+template <typename V>
+struct database_map: std::map<database, V>
+{
+ typedef std::map<database, V> base_type;
+
+ using base_type::operator[];
+
+ V const&
+ operator[] (database const& k) const
+ {
+ typename base_type::const_iterator i (this->find (k));
+ assert (i != this->end ());
+ return i->second;
+ }
+};
+
+//
+//
+struct multi_database
+{
+ enum value
+ {
+ // Keep in alphabetic order.
+ //
+ dynamic,
+ static_,
+ disabled // Special value.
+ };
+
+ multi_database (value v = disabled) : v_ (v) {}
+ operator value () const {return v_;}
+
+ const char*
+ string () const;
+
+private:
+ value v_;
+};
+
+std::istream&
+operator>> (std::istream&, multi_database&);
+
+std::ostream&
+operator<< (std::ostream&, multi_database);
+
+//
+//
struct schema_format
{
enum value
diff --git a/odb/options.cli b/odb/options.cli
index cad5db7..61d8371 100644
--- a/odb/options.cli
+++ b/odb/options.cli
@@ -45,11 +45,26 @@ class options
//
// Plugin options.
//
- ::database --database | -d
+ std::vector< ::database > --database | -d
{
"<db>",
"Generate code for the <db> database. Valid values are \cb{mssql},
- \cb{mysql}, \cb{oracle}, \cb{pgsql}, and \cb{sqlite}."
+ \cb{mysql}, \cb{oracle}, \cb{pgsql}, \cb{sqlite}, and \cb{common}."
+ };
+
+ ::multi_database --multi-database | -m = ::multi_database::disabled
+ {
+ "<type>",
+ "Enable multi-database support and specify its type. Valid values
+ for this option are \cb{static} and \cb{dynamic}."
+ };
+
+ ::database --default-database
+ {
+ "<db>",
+ "When static multi-database support is used, specify the database that
+ should be made the default. When dynamic multi-database support is used,
+ \cb{common} is always made the default database."
};
bool --generate-query | -q
@@ -239,14 +254,21 @@ class options
generated files."
};
- std::string --odb-file-suffix = "-odb"
+ database_map<std::string> --odb-file-suffix
{
"<suffix>",
"Use <suffix> instead of the default \cb{-odb} to construct the names
of the generated C++ files."
};
- std::string --schema-file-suffix = "-schema"
+ database_map<std::string> --sql-file-suffix
+ {
+ "<suffix>",
+ "Use <suffix> to construct the name of the generated schema SQL file.
+ By default no suffix is used."
+ };
+
+ database_map<std::string> --schema-file-suffix
{
"<suffix>",
"Use <suffix> instead of the default \cb{-schema} to construct the name
diff --git a/odb/plugin.cxx b/odb/plugin.cxx
index 1d73b7f..c5dcc89 100644
--- a/odb/plugin.cxx
+++ b/odb/plugin.cxx
@@ -268,7 +268,7 @@ plugin_init (plugin_name_args* plugin_info, plugin_gcc_version*)
cli::argv_file_scanner scan (argc, &argv[0], oi, 3);
options ops (scan);
assert (ops.database_specified ());
- db = ops.database ();
+ db = ops.database ()[0];
}
profile_data pd (profile_paths_, db, "odb plugin");
diff --git a/odb/processor.cxx b/odb/processor.cxx
index 0299ad5..616eddc 100644
--- a/odb/processor.cxx
+++ b/odb/processor.cxx
@@ -2,15 +2,1147 @@
// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
+#include <odb/gcc.hxx>
+
#include <iostream>
+#include <odb/common.hxx>
+#include <odb/lookup.hxx>
#include <odb/context.hxx>
+#include <odb/cxx-lexer.hxx>
#include <odb/processor.hxx>
+#include <odb/diagnostics.hxx>
#include <odb/relational/processor.hxx>
using namespace std;
+namespace
+{
+ struct data_member: traversal::data_member, context
+ {
+ virtual void
+ traverse (semantics::data_member& m)
+ {
+ if (transient (m))
+ return;
+
+ process_access (m, "get");
+ process_access (m, "set");
+ }
+
+ //
+ // 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)
+ {
+ // 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;
+ }
+ // 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 ();
+ }
+ }
+ }
+ }
+ };
+
+ struct class_: traversal::class_, context
+ {
+ class_ ()
+ : std_string_ (0), std_string_hint_ (0), access_ (0)
+ {
+ *this >> member_names_ >> member_;
+
+ // 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);
+ }
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ class_kind_type k (class_kind (c));
+
+ 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);
+
+ if (k == class_object)
+ traverse_object (c);
+
+ names (c);
+ }
+
+ //
+ // Object.
+ //
+
+ virtual void
+ traverse_object (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 ());
+
+ // 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);
+ }
+ }
+ }
+
+ 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:
+ data_member member_;
+ traversal::names member_names_;
+
+ cxx_string_lexer lex_;
+ cxx_string_lexer nlex_; // Nested lexer.
+
+ semantics::type* std_string_;
+ semantics::names* std_string_hint_;
+
+ tree access_; // odb::access node.
+ };
+}
+
void processor::
process (options const& ops,
features& f,
@@ -19,10 +1151,49 @@ process (options const& ops,
{
try
{
- // Process types.
- //
auto_ptr<context> ctx (create_context (cerr, unit, ops, f, 0));
- relational::process ();
+
+ // Common processing.
+ //
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ typedefs unit_typedefs (true);
+ traversal::namespace_ ns;
+ class_ c;
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+ unit >> unit_typedefs >> c;
+
+ traversal::defines ns_defines;
+ typedefs ns_typedefs (true);
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+ ns >> ns_typedefs >> c;
+
+ unit.dispatch (ctx->unit);
+ }
+
+ // Database-specific processing.
+ //
+ switch (ops.database ()[0])
+ {
+ case database::common:
+ {
+ break;
+ }
+ case database::mssql:
+ case database::mysql:
+ case database::oracle:
+ case database::pgsql:
+ case database::sqlite:
+ {
+ relational::process ();
+ break;
+ }
+ }
}
catch (operation_failed const&)
{
diff --git a/odb/profile.cxx b/odb/profile.cxx
index fedd7a9..03bf8a4 100644
--- a/odb/profile.cxx
+++ b/odb/profile.cxx
@@ -12,8 +12,6 @@
using namespace std;
-
-
static bool
exist (profile_data::path const& p)
{
@@ -64,6 +62,12 @@ profile_search (char const* prof, void* arg)
if (i == end)
{
+ // Ignore the case where we didn't find the profile and this is the
+ // common database.
+ //
+ if (pd->db == database::common)
+ return string ();
+
cerr << pd->name << ": error: unable to locate options file for profile '"
<< prof << "'" << endl;
throw profile_failure ();
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_;
};
}
diff --git a/odb/validator.cxx b/odb/validator.cxx
index aba82a5..d0b9ee2 100644
--- a/odb/validator.cxx
+++ b/odb/validator.cxx
@@ -821,233 +821,13 @@ namespace
// 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),
- data_member_ (valid),
- object_no_id_members_ (valid),
- composite_id_members_ (valid),
- view_members_ (valid)
+ : valid_ (valid), has_lt_operator_ (0)
{
- *this >> data_member_names_ >> data_member_;
-
- // Find the has_lt_operator function template..
+ // Find the has_lt_operator function template.
//
- has_lt_operator_ = 0;
-
tree odb (
lookup_qualified_name (
global_namespace, get_identifier ("odb"), false, false));
@@ -1098,148 +878,79 @@ namespace
virtual void
traverse_object (type& c)
{
- semantics::data_member* id (id_member (c));
-
- if (id != 0)
+ if (semantics::data_member* id = id_member (c))
{
- 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;
+ semantics::type& t (utype (*id));
- valid_ = false;
- }
+ // If this is a session object, make sure that the id type can
+ // be compared.
+ //
+ if (session (c) && has_lt_operator_ != 0)
+ {
+ tree args (make_tree_vec (1));
+ TREE_VEC_ELT (args, 0) = t.tree_node ();
- // Make sure we don't have any containers or pointers in this
- // composite value type.
- //
- if (valid_)
- {
- composite_id_members_.traverse (*cm);
+ tree inst (
+ instantiate_template (
+ has_lt_operator_, args, tf_none));
- if (!valid_)
- os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": info: composite id is defined here" << endl;
- }
+ bool v (inst != error_mark_node);
- // Check that the composite value type is default-constructible.
- //
- if (!cm->default_ctor ())
+ if (v &&
+ DECL_TEMPLATE_INSTANTIATION (inst) &&
+ !DECL_TEMPLATE_INSTANTIATED (inst))
{
- 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;
+ // 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;
- os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": info: composite id is defined here" << endl;
+ instantiate_decl (inst, false, false);
- valid_ = false;
+ global_dc->printer->buffer->stream = s;
+ v = (ec == errorcount);
}
- // If this is a session object, make sure that the composite
- // value can be compared.
- //
- if (session (c) && has_lt_operator_ != 0)
+ if (!v)
{
- tree args (make_tree_vec (1));
- TREE_VEC_ELT (args, 0) = cm->tree_node ();
+ os << t.file () << ":" << t.line () << ":" << t.column ()
+ << ": error: value type that is used as object id in "
+ << "persistent class with session support does not define "
+ << "the less than (<) comparison" << endl;
- tree inst (
- instantiate_template (
- has_lt_operator_, args, tf_none));
+ os << t.file () << ":" << t.line () << ":" << t.column ()
+ << ": info: provide operator< for this value type" << endl;
- 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 << cm->file () << ":" << cm->line () << ":" << cm->column ()
- << ": error: composite value type that is used as object id "
- << "in persistent class with session support does not "
- << "define the less than (<) comparison"
- << endl;
-
- os << cm->file () << ":" << cm->line () << ":" << cm->column ()
- << ": info: provide operator< for this value type" << endl;
-
- os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": info: composite id is defined here" << endl;
+ os << id->file () << ":" << id->line () << ":" << id->column ()
+ << ": info: id member is defined here" << endl;
- os << c.file () << ":" << c.line () << ":" << c.column ()
- << ": info: persistent class is defined here" << endl;
+ os << c.file () << ":" << c.line () << ":" << c.column ()
+ << ": info: persistent class is defined here" << endl;
- valid_ = false;
- }
+ 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);
}
virtual void
- traverse_view (type& c)
+ traverse_view (type&)
{
- // Make sure we don't have any containers or object pointers.
- //
- view_members_.traverse (c);
-
- names (c);
}
virtual void
- traverse_composite (type& c)
+ traverse_composite (type&)
{
- names (c);
}
bool& valid_;
tree has_lt_operator_;
-
- 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_;
};
}
@@ -1251,6 +962,7 @@ validate (options const& ops,
unsigned short pass)
{
bool valid (true);
+ database db (ops.database ()[0]);
// Validate options.
//
@@ -1263,6 +975,25 @@ validate (options const& ops,
valid = false;
}
+ // Multi-database support options.
+ //
+ if (ops.multi_database () == multi_database::dynamic &&
+ ops.default_database_specified () &&
+ ops.default_database () != database::common)
+ {
+ cerr << "error: when dynamic multi-database support is used, the " <<
+ "default database can only be 'common'" << endl;
+ valid = false;
+ }
+
+ if (db == database::common &&
+ ops.multi_database () == multi_database::disabled)
+ {
+ cerr << "error: 'common' database is only valid with multi-database " <<
+ "support enabled" << endl;
+ valid = false;
+ }
+
if (!valid)
throw failed ();
@@ -1319,13 +1050,29 @@ validate (options const& ops,
if (!valid)
throw failed ();
- try
+ switch (db)
{
- relational::validator v;
- v.validate (ops, f, u, p, pass);
- }
- catch (relational::validator::failed const&)
- {
- throw failed ();
+ case database::common:
+ {
+ break;
+ }
+ case database::mssql:
+ case database::mysql:
+ case database::oracle:
+ case database::pgsql:
+ case database::sqlite:
+ {
+ try
+ {
+ relational::validator v;
+ v.validate (ops, f, u, p, pass);
+ }
+ catch (relational::validator::failed const&)
+ {
+ throw failed ();
+ }
+
+ break;
+ }
}
}