aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-04-25 15:02:43 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-04-25 15:02:43 +0200
commit1a6a0652a6ef5b319cfc8ad05a0acee6910f7560 (patch)
tree40605db91ed90c342a9074308bd7406008b4f10b
parent9c5b2f928699a6752d7c3d1a062bac7efc247c64 (diff)
Add support for abstract object types
-rw-r--r--odb/common.cxx16
-rw-r--r--odb/context.cxx2
-rw-r--r--odb/context.hxx26
-rw-r--r--odb/pragma.cxx15
-rw-r--r--odb/relational/header.hxx189
-rw-r--r--odb/relational/inline.hxx122
-rw-r--r--odb/relational/mysql/common.cxx2
-rw-r--r--odb/relational/schema.hxx6
-rw-r--r--odb/relational/source.hxx283
-rw-r--r--odb/relational/sqlite/common.cxx2
-rw-r--r--odb/relational/type-processor.cxx22
-rw-r--r--odb/tracer/header.cxx2
-rw-r--r--odb/tracer/inline.cxx2
-rw-r--r--odb/tracer/source.cxx2
14 files changed, 407 insertions, 284 deletions
diff --git a/odb/common.cxx b/odb/common.cxx
index 20fd354..2c23e76 100644
--- a/odb/common.cxx
+++ b/odb/common.cxx
@@ -56,6 +56,9 @@ traverse (semantics::class_& c)
{
prev = context::object;
context::object = &c;
+
+ if (context::top_object == 0)
+ context::top_object = &c;
}
if (obj && build_table_prefix_)
@@ -89,7 +92,12 @@ traverse (semantics::class_& c)
}
if (obj)
+ {
+ if (prev == 0)
+ context::top_object = 0;
+
context::object = prev;
+ }
}
void object_members_base::member::
@@ -234,6 +242,9 @@ traverse (semantics::class_& c)
{
prev = context::object;
context::object = &c;
+
+ if (context::top_object == 0)
+ context::top_object = &c;
}
if (obj)
@@ -242,7 +253,12 @@ traverse (semantics::class_& c)
composite (0, c);
if (obj)
+ {
+ if (prev == 0)
+ context::top_object = 0;
+
context::object = prev;
+ }
if (f && !member_.first_)
flush ();
diff --git a/odb/context.cxx b/odb/context.cxx
index 8a85dcd..d281090 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -113,6 +113,7 @@ context (ostream& os_,
keyword_set (data_->keyword_set_),
embedded_schema (ops.generate_schema () &&
ops.schema_format ().count (schema_format::embedded)),
+ top_object (data_->top_object_),
object (data_->object_)
{
assert (current_ == 0);
@@ -131,6 +132,7 @@ context ()
db (current ().db),
keyword_set (current ().keyword_set),
embedded_schema (current ().embedded_schema),
+ top_object (current ().top_object),
object (current ().object)
{
}
diff --git a/odb/context.hxx b/odb/context.hxx
index a09d040..9878bcb 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -105,7 +105,10 @@ public:
static bool
abstract (semantics::class_& c)
{
- return c.count ("abstract");
+ // If a class is abstract in the C++ sense then it is also abstract in
+ // the database sense.
+ //
+ return c.abstract () || c.count ("abstract");
}
// Database names and types.
@@ -179,12 +182,12 @@ public:
static size_t
out_column_count (semantics::class_&);
- static semantics::data_member&
+ static semantics::data_member*
id_member (semantics::class_& c)
{
- // Set by the validator.
+ // Set by the validator. May not be there for abstract objects.
//
- return *c.get<semantics::data_member*> ("id-member");
+ return c.get<semantics::data_member*> ("id-member", 0);
}
// Object pointer information.
@@ -363,7 +366,14 @@ public:
bool embedded_schema;
- semantics::class_*& object; // Object currently being traversed.
+ // Outermost object currently being traversed.
+ //
+ semantics::class_*& top_object;
+
+ // Object currently being traversed. It can be the same as top_object
+ // or it can a base of top_object.
+ //
+ semantics::class_*& object;
struct db_type_type
{
@@ -416,12 +426,16 @@ protected:
{
virtual
~data () {}
- data (std::ostream& os): os_ (os.rdbuf ()), object_ (0) {}
+ data (std::ostream& os)
+ : os_ (os.rdbuf ()), top_object_ (0), object_ (0)
+ {
+ }
public:
std::ostream os_;
std::stack<std::streambuf*> os_stack_;
+ semantics::class_* top_object_;
semantics::class_* object_;
keyword_set_type keyword_set_;
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index 8cfc3fa..d8f3aef 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -128,7 +128,8 @@ check_decl_type (tree d, string const& name, string const& p, location_t l)
}
}
else if (p == "object" ||
- p == "pointer")
+ p == "pointer" ||
+ p == "abstract")
{
if (tc != RECORD_TYPE)
{
@@ -365,6 +366,18 @@ handle_pragma (cpp_reader* reader,
tt = pragma_lex (&t);
}
+ else if (p == "abstract")
+ {
+ // abstract
+ //
+
+ // Make sure we've got the correct declaration type.
+ //
+ if (decl != 0 && !check_decl_type (decl, decl_name, p, loc))
+ return;
+
+ tt = pragma_lex (&t);
+ }
else if (p == "id")
{
// id
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index 5ad7d2e..3ecc8d8 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -730,11 +730,12 @@ namespace relational
virtual void
traverse_object (type& c)
{
+ bool abst (abstract (c));
string const& type (c.fq_name ());
- semantics::data_member& id (id_member (c));
- bool auto_id (id.count ("auto"));
- bool base_id (&id.scope () != &c); // Id comes from a base class.
+ semantics::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.
os << "// " << c.name () << endl
<< "//" << endl;
@@ -751,109 +752,76 @@ namespace relational
// id_type & id_image_type
//
- if (base_id)
+ if (id != 0)
{
- string const& base (id.scope ().fq_name ());
+ if (base_id)
+ {
+ string const& base (id->scope ().fq_name ());
- os << "typedef object_traits< " << base << " >::id_type id_type;"
- << endl
- << "typedef object_traits< " << base << " >::id_image_type " <<
- "id_image_type;"
- << endl;
- }
- else
- {
- os << "typedef " << id.type ().fq_name (id.belongs ().hint ()) <<
- " id_type;"
- << endl;
+ os << "typedef object_traits< " << base << " >::id_type id_type;"
+ << endl
+ << "typedef object_traits< " << base << " >::id_image_type " <<
+ "id_image_type;"
+ << endl;
+ }
+ else
+ {
+ os << "typedef " << id->type ().fq_name (id->belongs ().hint ()) <<
+ " id_type;"
+ << endl;
- os << "struct id_image_type"
- << "{";
+ os << "struct id_image_type"
+ << "{";
- id_image_member_->traverse (id);
+ id_image_member_->traverse (*id);
- os << "std::size_t version;"
- << "};";
+ os << "std::size_t version;"
+ << "};";
+ }
}
// image_type
//
image_type_->traverse (c);
- // query types
//
+ // Query (abstract and concrete).
+ //
+
if (options.generate_query ())
{
// query_columns
//
query_type_->traverse (c);
-
- // query_base_type
- //
- os << "typedef " << db << "::query query_base_type;"
- << endl;
-
- // query_type
- //
- os << "struct query_type: query_base_type, query_columns"
- << "{"
- << "query_type ();"
- << "query_type (const std::string&);"
- << "query_type (const query_base_type&);"
- << "};";
}
- // column_count
- //
- os << "static const std::size_t in_column_count = " <<
- in_column_count (c) << "UL;"
- << "static const std::size_t out_column_count = " <<
- out_column_count (c) << "UL;"
- << endl;
-
- // Statements.
- //
- os << "static const char* const persist_statement;"
- << "static const char* const find_statement;"
- << "static const char* const update_statement;"
- << "static const char* const erase_statement;";
-
- if (options.generate_query ())
- os << "static const char* const query_clause;";
-
- os << endl;
-
//
- // Containers.
+ // Containers (abstract and concrete).
//
- // Traits types.
- //
{
instance<container_traits> t (c);
t->traverse (c);
}
- // Statement cache (forward declaration).
- //
- os << "struct container_statement_cache_type;"
- << endl;
-
//
- // Functions.
+ // Functions (abstract and concrete).
//
// id ()
//
- os << "static id_type" << endl
- << "id (const object_type&);"
- << endl;
-
- if (options.generate_query ())
+ if (id != 0)
+ {
os << "static id_type" << endl
- << "id (const image_type&);"
+ << "id (const object_type&);"
<< endl;
+ if (options.generate_query ())
+ os << "static id_type" << endl
+ << "id (const image_type&);"
+ << endl;
+ }
+
// grow ()
//
os << "static bool" << endl
@@ -868,9 +836,12 @@ namespace relational
// bind (id_image_type)
//
- os << "static void" << endl
- << "bind (" << bind_vector << ", id_image_type&);"
- << endl;
+ if (id != 0)
+ {
+ os << "static void" << endl
+ << "bind (" << bind_vector << ", id_image_type&);"
+ << endl;
+ }
// init (image, object)
//
@@ -886,10 +857,76 @@ namespace relational
// init (id_image, id)
//
- os << "static void" << endl
- << "init (id_image_type&, const id_type&);"
+ if (id != 0)
+ {
+ os << "static void" << endl
+ << "init (id_image_type&, const id_type&);"
+ << endl;
+ }
+
+ //
+ // The rest only applies to concrete objects.
+ //
+ if (abst)
+ {
+ os << "};";
+ return;
+ }
+
+ //
+ // Query (concrete).
+ //
+
+ if (options.generate_query ())
+ {
+ // query_base_type
+ //
+ os << "typedef " << db << "::query query_base_type;"
+ << endl;
+
+ // query_type
+ //
+ os << "struct query_type: query_base_type, query_columns"
+ << "{"
+ << "query_type ();"
+ << "query_type (const std::string&);"
+ << "query_type (const query_base_type&);"
+ << "};";
+ }
+
+ //
+ // Containers (concrete).
+ //
+
+ // Statement cache (forward declaration).
+ //
+ os << "struct container_statement_cache_type;"
+ << endl;
+
+ // column_count
+ //
+ os << "static const std::size_t in_column_count = " <<
+ in_column_count (c) << "UL;"
+ << "static const std::size_t out_column_count = " <<
+ out_column_count (c) << "UL;"
<< endl;
+ // Statements.
+ //
+ os << "static const char* const persist_statement;"
+ << "static const char* const find_statement;"
+ << "static const char* const update_statement;"
+ << "static const char* const erase_statement;";
+
+ if (options.generate_query ())
+ os << "static const char* const query_clause;";
+
+ os << endl;
+
+ //
+ // Functions (concrete).
+ //
+
// persist ()
//
os << "static void" << endl
diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx
index 9e76dea..73e0112 100644
--- a/odb/relational/inline.hxx
+++ b/odb/relational/inline.hxx
@@ -32,16 +32,80 @@ namespace relational
virtual void
traverse_object (type& c)
{
+ bool abst (abstract (c));
string const& type (c.fq_name ());
string traits ("access::object_traits< " + type + " >");
- semantics::data_member& id (id_member (c));
- bool base_id (&id.scope () != &c); // Id comes from a base class.
+ semantics::data_member* id (id_member (c));
+ bool base_id (id ? &id->scope () != &c : false); // Comes from base.
os << "// " << c.name () << endl
<< "//" << endl
<< endl;
+ if (id != 0)
+ {
+ // id (object_type)
+ //
+ os << "inline" << endl
+ << traits << "::id_type" << endl
+ << traits << "::" << endl
+ << "id (const object_type& obj)"
+ << "{";
+
+ if (base_id)
+ os << "return object_traits< " << id->scope ().fq_name () <<
+ " >::id (obj);";
+ else
+ os << "return obj." << id->name () << ";";
+
+ os << "}";
+
+ // id (image_type)
+ //
+ if (options.generate_query () && base_id)
+ {
+ os << "inline" << endl
+ << traits << "::id_type" << endl
+ << traits << "::" << endl
+ << "id (const image_type& i)"
+ << "{"
+ << "return object_traits< " << id->scope ().fq_name () <<
+ " >::id (i);"
+ << "}";
+ }
+
+ // bind (id_image_type)
+ //
+ if (base_id)
+ {
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "bind (" << bind_vector << " b, id_image_type& i)"
+ << "{"
+ << "object_traits< " << id->scope ().fq_name () <<
+ " >::bind (b, i);"
+ << "}";
+ }
+
+ if (base_id)
+ {
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "init (id_image_type& i, const id_type& id)"
+ << "{"
+ << "object_traits< " << id->scope ().fq_name () <<
+ " >::init (i, id);"
+ << "}";
+ }
+ }
+
+ //
+ // The rest only applies to concrete objects.
+ //
+ if (abst)
+ return;
+
// query_type
//
if (options.generate_query ())
@@ -67,60 +131,6 @@ namespace relational
<< "}";
}
- // id (object_type)
- //
- os << "inline" << endl
- << traits << "::id_type" << endl
- << traits << "::" << endl
- << "id (const object_type& obj)"
- << "{";
-
- if (base_id)
- os << "return object_traits< " << id.scope ().fq_name () <<
- " >::id (obj);";
- else
- os << "return obj." << id.name () << ";";
-
- os << "}";
-
- // id (image_type)
- //
- if (options.generate_query () && base_id)
- {
- os << "inline" << endl
- << traits << "::id_type" << endl
- << traits << "::" << endl
- << "id (const image_type& i)"
- << "{"
- << "return object_traits< " << id.scope ().fq_name () <<
- " >::id (i);"
- << "}";
- }
-
- // bind (id_image_type)
- //
- if (base_id)
- {
- os << "inline" << endl
- << "void " << traits << "::" << endl
- << "bind (" << bind_vector << " b, id_image_type& i)"
- << "{"
- << "object_traits< " << id.scope ().fq_name () <<
- " >::bind (b, i);"
- << "}";
- }
-
- if (base_id)
- {
- os << "inline" << endl
- << "void " << traits << "::" << endl
- << "init (id_image_type& i, const id_type& id)"
- << "{"
- << "object_traits< " << id.scope ().fq_name () <<
- " >::init (i, id);"
- << "}";
- }
-
// load_()
//
if (!has_a (c, test_container))
diff --git a/odb/relational/mysql/common.cxx b/odb/relational/mysql/common.cxx
index c9a33e4..5ddd27d 100644
--- a/odb/relational/mysql/common.cxx
+++ b/odb/relational/mysql/common.cxx
@@ -59,7 +59,7 @@ namespace relational
if (semantics::class_* c = object_pointer (t))
{
- member_info mi (m, id_member (*c).type (), var, fq_type_override_);
+ member_info mi (m, id_member (*c)->type (), var, fq_type_override_);
mi.st = &st;
if (pre (mi))
{
diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx
index 6c481da..9e04b77 100644
--- a/odb/relational/schema.hxx
+++ b/odb/relational/schema.hxx
@@ -136,7 +136,7 @@ namespace relational
if (c.file () != unit.file ())
return;
- if (!c.count ("object"))
+ if (!c.count ("object") || abstract (c))
return;
string const& name (table_name (c));
@@ -192,7 +192,7 @@ namespace relational
if (semantics::class_* c = object_pointer (member_type (m, prefix_)))
{
os << " REFERENCES " << quote_id (table_name (*c)) << " (" <<
- quote_id (column_name (id_member (*c))) << ")";
+ quote_id (column_name (*id_member (*c))) << ")";
}
return true;
@@ -369,7 +369,7 @@ namespace relational
if (c.file () != unit.file ())
return;
- if (!c.count ("object"))
+ if (!c.count ("object") || abstract (c))
return;
string const& name (table_name (c));
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index 5b2ec8d..9a23ca4 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -111,7 +111,7 @@ namespace relational
}
else
{
- semantics::data_member& id (id_member (*c));
+ semantics::data_member& id (*id_member (*c));
column (id, "",
table_name_.empty () ? table_name_ : table_qname (*c),
column_qname (id));
@@ -172,7 +172,7 @@ namespace relational
object_joins (semantics::class_& scope, bool query)
: query_ (query),
table_ (table_qname (scope)),
- id_ (id_member (scope))
+ id_ (*id_member (scope))
{
}
@@ -240,7 +240,7 @@ namespace relational
dt = ct;
string const& id (column_qname (*im, "id", "object_id"));
- dcond << dt << '.' << column_qname (id_member (*c)) << " = " <<
+ dcond << dt << '.' << column_qname (*id_member (*c)) << " = " <<
t << '.' << id;
}
}
@@ -259,7 +259,7 @@ namespace relational
//
t = table_qname (*c);
- cond << t << '.' << column_qname (id_member (*c)) << " = _." <<
+ cond << t << '.' << column_qname (*id_member (*c)) << " = _." <<
quote_id (col_name);
}
@@ -703,7 +703,7 @@ namespace relational
// many(i)-to-one
//
inv_table = table_qname (*c);
- inv_id = column_qname (id_member (*c));
+ inv_id = column_qname (*id_member (*c));
inv_fid = column_qname (*im);
}
@@ -873,8 +873,6 @@ namespace relational
// bind()
//
{
- instance<bind_member> bind_id ("id_", "id");
-
// bind (cond_image_type)
//
os << "void " << scope << "::" << endl
@@ -1795,160 +1793,57 @@ namespace relational
virtual void
traverse_object (type& c)
{
+ bool abst (abstract (c));
string const& type (c.fq_name ());
string traits ("access::object_traits< " + type + " >");
bool grow (context::grow (c));
- semantics::data_member& id (id_member (c));
- bool auto_id (id.count ("auto"));
- bool grow_id (context::grow (id));
- bool base_id (&id.scope () != &c); // Id comes from a base class.
+ semantics::data_member* id (id_member (c));
+ bool auto_id (id ? id->count ("auto") : false);
+ bool grow_id (id ? context::grow (*id) : false);
+ bool base_id (id ? &id->scope () != &c : false); // Comes from base.
os << "// " << c.name () << endl
<< "//" << endl
<< endl;
//
- // Containers.
- //
- bool straight_containers (has_a (c, test_straight_container));
- bool containers (straight_containers || has_a (c, test_container));
-
- // Statement cache (definition).
+ // Query.
//
- {
- os << "struct " << traits << "::container_statement_cache_type"
- << "{";
-
- instance<container_cache_members> cm;
- cm->traverse (c);
-
- os << (containers ? "\n" : "")
- << "container_statement_cache_type (" << db << "::connection&" <<
- (containers ? " c" : "") << ")";
-
- instance<container_cache_init_members> im;
- im->traverse (c);
-
- os << "{"
- << "}"
- << "};";
- }
-
- // Traits types.
- //
- if (containers)
- {
- instance<container_traits> t (c);
- t->traverse (c);
- }
- // query columns
- //
if (options.generate_query ())
{
instance<query_columns> t (c);
t->traverse (c);
}
- string const& table (table_qname (c));
- string const& id_col (column_qname (id));
-
- // persist_statement
//
- os << "const char* const " << traits << "::persist_statement =" << endl
- << strlit ("INSERT INTO " + table + " (") << endl;
-
- {
- instance<object_columns> t (false);
- t->traverse (c);
- }
-
- string values;
- for (size_t i (0), n (in_column_count (c)); i < n; ++i)
- values += i != 0 ? ",?" : "?";
-
- os << strlit (") VALUES (" + values + ")") << ";"
- << endl;
-
- // find_statement
- //
- os << "const char* const " << traits << "::find_statement =" << endl
- << strlit ("SELECT ") << endl;
-
- {
- instance<object_columns> t (table, true);
- t->traverse (c);
- }
-
- os << strlit (" FROM " + table + " AS _") << endl;
-
- {
- bool f (false);
- instance<object_joins> t (c, f); // @@ (im)perfect forwarding
- t->traverse (c);
- t->write ();
- }
-
- os << strlit (" WHERE _." + id_col + " = ?") << ";"
- << endl;
-
- // update_statement
+ // Containers (abstract and concrete).
//
- os << "const char* const " << traits << "::update_statement =" << endl
- << strlit ("UPDATE " + table + " SET ") << endl;
+ bool straight_containers (has_a (c, test_straight_container));
+ bool containers (straight_containers || has_a (c, test_container));
+ if (containers)
{
- instance<object_columns> t (false, true, " = ?");
+ instance<container_traits> t (c);
t->traverse (c);
}
- os << strlit (" WHERE " + id_col + " = ?") << ";"
- << endl;
-
- // erase_statement
//
- os << "const char* const " << traits << "::erase_statement =" << endl
- << strlit ("DELETE FROM " + table) << endl
- << strlit (" WHERE " + id_col + " = ?") << ";"
- << endl;
-
- // query_clause
+ // Functions (abstract and concrete).
//
- if (options.generate_query ())
- {
- bool t (true);
- instance<object_joins> oj (c, t); //@@ (im)perfect forwarding
- oj->traverse (c);
-
- // We only need DISTINCT if there are joins (object pointers)
- // and can optimize it out otherwise.
- //
- os << "const char* const " << traits << "::query_clause =" << endl
- << strlit (oj->count () ? "SELECT DISTINCT " : "SELECT ") << endl;
-
- {
- instance<object_columns> oc (table, true);
- oc->traverse (c);
- }
-
- os << strlit (" FROM " + table + " AS _") << endl;
- oj->write ();
- os << strlit (" ") << ";"
- << endl;
- }
// id (image_type)
//
- if (options.generate_query () && !base_id)
+ if (id != 0 && options.generate_query () && !base_id)
{
os << traits << "::id_type" << endl
<< traits << "::" << endl
<< "id (const image_type& i)"
<< "{"
<< "id_type id;";
- init_id_value_member_->traverse (id);
+ init_id_value_member_->traverse (*id);
os << "return id;"
<< "}";
}
@@ -1988,13 +1883,13 @@ namespace relational
// bind (id_image_type)
//
- if (!base_id)
+ if (id != 0 && !base_id)
{
os << "void " << traits << "::" << endl
<< "bind (" << bind_vector << " b, id_image_type& i)"
<< "{"
<< "std::size_t n (0);";
- bind_id_member_->traverse (id);
+ bind_id_member_->traverse (*id);
os << "}";
}
@@ -2032,7 +1927,7 @@ namespace relational
// init (id_image, id)
//
- if (!base_id)
+ if (id != 0 && !base_id)
{
os << "void " << traits << "::" << endl
<< "init (id_image_type& i, const id_type& id)"
@@ -2041,7 +1936,7 @@ namespace relational
if (grow_id)
os << "bool grew (false);";
- init_id_image_member_->traverse (id);
+ init_id_image_member_->traverse (*id);
if (grow_id)
os << endl
@@ -2051,6 +1946,128 @@ namespace relational
os << "}";
}
+ //
+ // The rest only applies to concrete objects.
+ //
+ if (abst)
+ return;
+
+ //
+ // Containers (concrete).
+ //
+
+ // Statement cache (definition).
+ //
+ {
+ os << "struct " << traits << "::container_statement_cache_type"
+ << "{";
+
+ instance<container_cache_members> cm;
+ cm->traverse (c);
+
+ os << (containers ? "\n" : "")
+ << "container_statement_cache_type (" << db << "::connection&" <<
+ (containers ? " c" : "") << ")";
+
+ instance<container_cache_init_members> im;
+ im->traverse (c);
+
+ os << "{"
+ << "}"
+ << "};";
+ }
+
+ //
+ // Statements.
+ //
+
+ string const& table (table_qname (c));
+ string const& id_col (column_qname (*id));
+
+ // persist_statement
+ //
+ os << "const char* const " << traits << "::persist_statement =" << endl
+ << strlit ("INSERT INTO " + table + " (") << endl;
+
+ {
+ instance<object_columns> t (false);
+ t->traverse (c);
+ }
+
+ string values;
+ for (size_t i (0), n (in_column_count (c)); i < n; ++i)
+ values += i != 0 ? ",?" : "?";
+
+ os << strlit (") VALUES (" + values + ")") << ";"
+ << endl;
+
+ // find_statement
+ //
+ os << "const char* const " << traits << "::find_statement =" << endl
+ << strlit ("SELECT ") << endl;
+
+ {
+ instance<object_columns> t (table, true);
+ t->traverse (c);
+ }
+
+ os << strlit (" FROM " + table + " AS _") << endl;
+
+ {
+ bool f (false);
+ instance<object_joins> t (c, f); // @@ (im)perfect forwarding
+ t->traverse (c);
+ t->write ();
+ }
+
+ os << strlit (" WHERE _." + id_col + " = ?") << ";"
+ << endl;
+
+ // update_statement
+ //
+ os << "const char* const " << traits << "::update_statement =" << endl
+ << strlit ("UPDATE " + table + " SET ") << endl;
+
+ {
+ instance<object_columns> t (false, true, " = ?");
+ t->traverse (c);
+ }
+
+ os << strlit (" WHERE " + id_col + " = ?") << ";"
+ << endl;
+
+ // erase_statement
+ //
+ os << "const char* const " << traits << "::erase_statement =" << endl
+ << strlit ("DELETE FROM " + table) << endl
+ << strlit (" WHERE " + id_col + " = ?") << ";"
+ << endl;
+
+ // query_clause
+ //
+ if (options.generate_query ())
+ {
+ bool t (true);
+ instance<object_joins> oj (c, t); //@@ (im)perfect forwarding
+ oj->traverse (c);
+
+ // We only need DISTINCT if there are joins (object pointers)
+ // and can optimize it out otherwise.
+ //
+ os << "const char* const " << traits << "::query_clause =" << endl
+ << strlit (oj->count () ? "SELECT DISTINCT " : "SELECT ") << endl;
+
+ {
+ instance<object_columns> oc (table, true);
+ oc->traverse (c);
+ }
+
+ os << strlit (" FROM " + table + " AS _") << endl;
+ oj->write ();
+ os << strlit (" ") << ";"
+ << endl;
+ }
+
// persist ()
//
os << "void " << traits << "::" << endl
@@ -2072,9 +2089,9 @@ namespace relational
if (auto_id)
{
- string const& n (id.name ());
+ string const& n (id->name ());
string var ("im." + n + (n[n.size () - 1] == '_' ? "" : "_"));
- init_auto_id (id, var);
+ init_auto_id (*id, var);
os << endl;
}
@@ -2090,7 +2107,7 @@ namespace relational
<< endl;
if (auto_id)
- os << "obj." << id.name () << " = static_cast<id_type> (st.id ());"
+ os << "obj." << id->name () << " = static_cast<id_type> (st.id ());"
<< endl;
if (straight_containers)
@@ -2098,7 +2115,7 @@ namespace relational
// Initialize id_image and binding.
//
os << "id_image_type& i (sts.id_image ());"
- << "init (i, obj." << id.name () << ");"
+ << "init (i, obj." << id->name () << ");"
<< endl
<< "binding& idb (sts.id_image_binding ());"
<< "if (i.version != sts.id_image_version () || idb.version == 0)"
@@ -2130,7 +2147,7 @@ namespace relational
// Initialize id image.
//
os << "id_image_type& i (sts.id_image ());"
- << "init (i, obj." << id.name () << ");"
+ << "init (i, obj." << id->name () << ");"
<< endl;
os << "binding& idb (sts.id_image_binding ());"
diff --git a/odb/relational/sqlite/common.cxx b/odb/relational/sqlite/common.cxx
index ef880ed..010e267 100644
--- a/odb/relational/sqlite/common.cxx
+++ b/odb/relational/sqlite/common.cxx
@@ -59,7 +59,7 @@ namespace relational
if (semantics::class_* c = object_pointer (t))
{
- member_info mi (m, id_member (*c).type (), var, fq_type_override_);
+ member_info mi (m, id_member (*c)->type (), var, fq_type_override_);
mi.st = &st;
if (pre (mi))
{
diff --git a/odb/relational/type-processor.cxx b/odb/relational/type-processor.cxx
index 18d411c..5c86b10 100644
--- a/odb/relational/type-processor.cxx
+++ b/odb/relational/type-processor.cxx
@@ -22,7 +22,7 @@ namespace relational
id_tree_type ()
{
context& c (context::current ());
- semantics::data_member& id (context::id_member (*c.object));
+ semantics::data_member& id (*context::id_member (*c.top_object));
return &id.type ();
}
@@ -30,7 +30,7 @@ namespace relational
id_column_type ()
{
context& c (context::current ());
- semantics::data_member& id (context::id_member (*c.object));
+ semantics::data_member& id (*context::id_member (*c.top_object));
return id.get<string> ("column-type");
}
@@ -118,7 +118,7 @@ namespace relational
// This is an object pointer. The column type is the pointed-to
// object id type. Except by default it can be NULL.
//
- semantics::data_member& id (id_member (*c));
+ semantics::data_member& id (*id_member (*c));
semantics::type& idt (id.type ());
if (type.empty () && id.count ("type"))
@@ -203,7 +203,7 @@ namespace relational
// This is an object pointer. The column type is the pointed-to
// object id type. Except by default it can be NULL.
//
- semantics::data_member& id (id_member (*c));
+ semantics::data_member& id (*id_member (*c));
semantics::type& idt (id.type ());
if (type.empty () && id.count ("type"))
@@ -660,6 +660,20 @@ namespace relational
throw generation_failed ();
}
+ // Make sure the pointed-to class is not abstract.
+ //
+ if (context::abstract (*c))
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column () << ": "
+ << "error: pointed-to class '" << c->fq_name () << "' "
+ << "is abstract" << endl;
+
+ os << c->file () << ":" << c->line () << ":" << c->column () << ": "
+ << "info: class '" << c->name () << "' is defined here" << endl;
+
+ throw generation_failed ();
+ }
+
if (m.count ("not-null") && !kp.empty ())
{
m.remove ("not-null");
diff --git a/odb/tracer/header.cxx b/odb/tracer/header.cxx
index 6973fe4..16bee82 100644
--- a/odb/tracer/header.cxx
+++ b/odb/tracer/header.cxx
@@ -26,7 +26,7 @@ namespace tracer
string const& type (c.fq_name ());
- semantics::data_member& id (id_member (c));
+ semantics::data_member& id (*id_member (c));
bool auto_id (id.count ("auto"));
os << "// " << c.name () << endl
diff --git a/odb/tracer/inline.cxx b/odb/tracer/inline.cxx
index 0abfb70..f4125a9 100644
--- a/odb/tracer/inline.cxx
+++ b/odb/tracer/inline.cxx
@@ -27,7 +27,7 @@ namespace tracer
string const& type (c.fq_name ());
string traits ("access::object_traits< " + type + " >");
- semantics::data_member& id (id_member (c));
+ semantics::data_member& id (*id_member (c));
os << "// " << c.name () << endl
<< "//" << endl
diff --git a/odb/tracer/source.cxx b/odb/tracer/source.cxx
index 5b26274..c25c1ee 100644
--- a/odb/tracer/source.cxx
+++ b/odb/tracer/source.cxx
@@ -27,7 +27,7 @@ namespace tracer
string const& type (c.fq_name ());
string traits ("access::object_traits< " + type + " >");
- semantics::data_member& id (id_member (c));
+ semantics::data_member& id (*id_member (c));
bool auto_id (id.count ("auto"));
os << "// " << c.name () << endl