aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-09-09 12:18:39 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-09-09 12:18:39 +0200
commite56ba020233ad7cb4762df300a6774db9195d817 (patch)
treefe392af07bab9d1fc19cb000e60f58cf39b3d746
parent164d595dba8cadbe3b889b6e809aec8a24a8d878 (diff)
New templated query_columns architecture
We also now use the correct separate "role"-base join approach instead of having a single merged join for each table.
-rw-r--r--odb/relational/common.cxx253
-rw-r--r--odb/relational/common.hxx27
-rw-r--r--odb/relational/header.cxx47
-rw-r--r--odb/relational/header.hxx321
-rw-r--r--odb/relational/pgsql/header.cxx26
-rw-r--r--odb/relational/pgsql/source.cxx32
-rw-r--r--odb/relational/source.hxx181
7 files changed, 567 insertions, 320 deletions
diff --git a/odb/relational/common.cxx b/odb/relational/common.cxx
index ae2e1f4..2cb525e 100644
--- a/odb/relational/common.cxx
+++ b/odb/relational/common.cxx
@@ -15,32 +15,123 @@ using namespace std;
namespace relational
{
+ // query_columns_base
+ //
+
+ query_columns_base::
+ query_columns_base ()
+ : decl_ (true)
+ {
+ }
+
+ query_columns_base::
+ query_columns_base (semantics::class_& c) //@@ context::{cur,top}_object
+ : decl_ (false)
+ {
+ scope_ = "query_columns_base< " + c.fq_name () + " >";
+ }
+
+ void query_columns_base::
+ traverse_object (semantics::class_& c)
+ {
+ // We don't want to traverse bases.
+ //
+ names (c);
+ }
+
+ void query_columns_base::
+ traverse_composite (semantics::data_member* m, semantics::class_& c)
+ {
+ // Base type.
+ //
+ if (m == 0)
+ {
+ object_columns_base::traverse_composite (m, c);
+ return;
+ }
+
+ // Don't generate an empty struct if we don't have any pointers.
+ //
+ if (!has_a (c, test_pointer))
+ return;
+
+ string name (public_name (*m));
+
+ if (decl_)
+ {
+ os << "// " << name << endl
+ << "//" << endl
+ << "struct " << name << "_base_"
+ << "{";
+
+ object_columns_base::traverse_composite (m, c);
+
+ os << "};";
+ }
+ else
+ {
+ string old_scope (scope_);
+ scope_ += "::" + name + "_base_";
+
+ object_columns_base::traverse_composite (m, c);
+
+ scope_ = old_scope;
+ }
+ }
+
+ bool query_columns_base::
+ traverse_column (semantics::data_member& m, string const& column, bool)
+ {
+ semantics::class_* c (object_pointer (m.type ()));
+
+ if (c == 0)
+ return false;
+
+ string name (public_name (m));
+
+ if (decl_)
+ os << "// " << name << endl
+ << "//" << endl
+ << "static const char " << name << "_alias_[];"
+ << endl
+ << "typedef" << endl
+ << "odb::pointer_query_columns< " << c->fq_name () << ", " <<
+ name << "_alias_ >" << endl
+ << name << ";"
+ << endl;
+ else
+ // For now use column name. This will become problematic when we
+ // add support for composite ids.
+ //
+ os << "const char " << scope_ << "::" << name << "_alias_[] =" << endl
+ << strlit (column) << ";"
+ << endl;
+
+ return true;
+ }
+
// query_columns
//
query_columns::
- query_columns ()
- : ptr_ (true), decl_ (true)
+ query_columns (bool ptr)
+ : ptr_ (ptr), decl_ (true)
{
}
query_columns::
- query_columns (semantics::class_& c) //@@ context::{cur,top}_object
- : ptr_ (true), decl_ (false)
+ query_columns (bool ptr, semantics::class_& c) //@@ context::{cur,top}_object
+ : ptr_ (ptr), decl_ (false)
{
- scope_ = "access::object_traits< " + c.fq_name () + " >::query_columns";
- table_ = default_table_ = table_qname (c);
+ scope_ = ptr ? "pointer_query_columns" : "query_columns";
+ scope_ += "< " + c.fq_name () + ", table >";
}
void query_columns::
traverse_object (semantics::class_& c)
{
- // We only want members for objects unless we are traversing a
- // pointer, in which case we need the whole thing.
+ // We don't want to traverse bases.
//
- if (!ptr_)
- inherits (c);
-
names (c);
}
@@ -61,8 +152,15 @@ namespace relational
{
os << "// " << name << endl
<< "//" << endl
- << "struct " << name
- << "{";
+ << "struct " << name;
+
+ // Derive from the base in query_columns_base. It contains columns
+ // for the pointer members.
+ //
+ if (!ptr_ && has_a (c, test_pointer))
+ os << ": " << name << "_base_";
+
+ os << "{";
object_columns_base::traverse_composite (m, c);
@@ -80,104 +178,55 @@ namespace relational
}
bool query_columns::
- traverse_column (semantics::data_member& m, string const& col_name, bool)
+ traverse_column (semantics::data_member& m, string const& column, bool)
{
- string name (public_name (m));
+ string mtype;
if (semantics::class_* c = object_pointer (m.type ()))
{
- // We cannot just typedef the query_type from the referenced
- // object for two reasons: (1) it may not be defined yet and
- // (2) it will contain columns for its own pointers which
- // won't work (for now we only support one level of indirection
- // in queries). So we will have to duplicate the columns (sans
- // the pointers).
- //
- // There are a number of problems with this approach: Regarding (1),
- // the class have to be defined during ODB compilation in which
- // case the ODB compiler will hunt down the #include statement
- // and add it to the generated code. Regarding (2), things get
- // complicated really quickly once we bring inheritance into
- // the picture (name conflicts, etc). Plus, it is nice to reuse
- // things. So the long-term solution is probably to make it a
- // template with the table name as an argument.
+ // If this is for the pointer_query_columns and the member is not
+ // inverse, then create the normal member corresponding to the id
+ // column. This will allow the user to check it for NULL or to
+ // compare ids. In case this is for query_columns, then the
+ // corresponding member is defined in query_columns_base.
//
+ if (!ptr_ || inverse (m))
+ return false;
- if (ptr_)
- {
- ptr_ = false;
-
- if (decl_)
- {
- os << "// " << name << endl
- << "//" << endl
- << "struct " << name
- << "{";
-
- traverse (*c);
-
- os << "};";
- }
- else
- {
- string old_scope (scope_), old_table (table_);
- scope_ += "::" + name;
- table_ = table_qname (*c);
- traverse (*c);
- table_ = old_table;
- scope_ = old_scope;
- }
-
- ptr_ = true;
- }
+ semantics::data_member& id (*id_member (*c));
+ mtype = id.type ().fq_name (id.belongs ().hint ());
+ }
+ else
+ mtype = m.type ().fq_name (m.belongs ().hint ());
+
+ string name (public_name (m));
+ string db_type_id (database_type_id (m));
+
+ string type (
+ string (db.string ()) + "::value_traits< "
+ + mtype + ", "
+ + db_type_id
+ + " >::query_type");
+
+ if (decl_)
+ {
+ os << "// " << name << endl
+ << "//" << endl
+ << "static const " << db << "::query_column<" << endl
+ << " " << type << "," << endl
+ << " " << db_type_id << " >" << endl
+ << name << ";"
+ << endl;
}
else
{
- string db_type_id (database_type_id (m));
-
- string type (
- string (db.string ()) + "::value_traits< "
- + m.type ().fq_name (m.belongs ().hint ()) + ", "
- + db_type_id
- + " >::query_type");
-
- if (decl_)
- {
- os << "// " << name << endl
- << "//" << endl
- << "static const " << db << "::query_column<" << endl
- << " " << type << "," << endl
- << " " << db_type_id << " >" << endl
- << name << ";"
- << endl;
- }
- else
- {
- // Leave the default table name unless we are generating members
- // for a referenced object.
- //
- string column;
-
- if (!ptr_)
- {
- // If this is a self-reference, use the special '_' alias.
- //
- if (table_ != default_table_)
- column = table_;
- else
- column = "_";
- }
-
- column += '.';
- column += quote_id (col_name);
-
- os << "const " << db << "::query_column<" << endl
- << " " << type << "," << endl
- << " " << db_type_id << " >" << endl
- << scope_ << "::" << name << " (" << endl
- << strlit (column) << ");"
- << endl;
- }
+ os << "template <const char* table>" << endl
+ << "const " << db << "::query_column<" << endl
+ << " " << type << "," << endl
+ << " " << db_type_id << " >" << endl
+ << scope_ << "::" << name << " (" << endl
+ << "table, " << strlit (column) << ");"
+ << endl;
}
return true;
diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx
index 8fc88e3..92edba6 100644
--- a/odb/relational/common.hxx
+++ b/odb/relational/common.hxx
@@ -54,12 +54,35 @@ namespace relational
//
//
+ struct query_columns_base: object_columns_base, virtual context
+ {
+ typedef query_columns_base base;
+
+ query_columns_base ();
+ query_columns_base (semantics::class_&);
+
+ virtual void
+ traverse_object (semantics::class_&);
+
+ virtual void
+ traverse_composite (semantics::data_member*, semantics::class_&);
+
+ virtual bool
+ traverse_column (semantics::data_member&, string const&, bool);
+
+ protected:
+ bool decl_;
+ string scope_;
+ };
+
+ //
+ //
struct query_columns: object_columns_base, virtual context
{
typedef query_columns base;
- query_columns ();
- query_columns (semantics::class_&);
+ query_columns (bool ptr);
+ query_columns (bool ptr, semantics::class_&);
virtual string
database_type_id (semantics::data_member&)
diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx
index c70ef27..11d3cf6 100644
--- a/odb/relational/header.cxx
+++ b/odb/relational/header.cxx
@@ -18,26 +18,45 @@ namespace relational
context ctx;
ostream& os (ctx.os);
- traversal::unit unit;
- traversal::defines unit_defines;
- traversal::namespace_ ns;
- instance<class_> c;
-
- unit >> unit_defines >> ns;
- unit_defines >> c;
-
- traversal::defines ns_defines;
-
- ns >> ns_defines >> ns;
- ns_defines >> c;
-
instance<include> i;
i->generate ();
os << "namespace odb"
<< "{";
- unit.dispatch (ctx.unit);
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ instance<class1> c;
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+
+ unit.dispatch (ctx.unit);
+ }
+
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ instance<class2> c;
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+
+ unit.dispatch (ctx.unit);
+ }
os << "}";
}
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index 30cb01e..cc89e9a 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -115,14 +115,17 @@ namespace relational
};
//
- // query_type
+ // query_columns_type
//
- struct query_base: traversal::class_, virtual context
+ struct query_columns_bases: traversal::class_, virtual context
{
- typedef query_base base;
+ typedef query_columns_bases base;
- query_base (): first_ (true) {}
+ query_columns_bases (bool ptr, bool first = true)
+ : ptr_ (ptr), first_ (first)
+ {
+ }
virtual void
traverse (type& c)
@@ -143,37 +146,156 @@ namespace relational
<< " ";
}
- os << "object_traits< " << c.fq_name () << " >::query_columns";
+ os << (ptr_ ? "pointer_query_columns" : "query_columns") <<
+ "< " << c.fq_name () << ", table >";
}
private:
+ bool ptr_;
bool first_;
};
- struct query_type: traversal::class_, virtual context
+ struct query_columns_base_aliases: traversal::class_, virtual context
{
- typedef query_type base;
+ typedef query_columns_base_aliases base;
+
+ query_columns_base_aliases (bool ptr)
+ : ptr_ (ptr)
+ {
+ }
virtual void
traverse (type& c)
{
- os << "struct query_columns";
+ // Ignore transient bases. Not used for views.
+ //
+ if (!object (c))
+ return;
- {
- instance<query_base> b;
- traversal::inherits i (*b);
- inherits (c, i);
- }
+ os << "// " << c.name () << endl
+ << "//" << endl
+ << "typedef " <<
+ (ptr_ ? "pointer_query_columns" : "query_columns") <<
+ "< " << c.fq_name () << ", table > " << c.name () << ";"
+ << endl;
+ }
- os << "{";
+ private:
+ bool ptr_;
+ };
+
+ struct query_columns_type: traversal::class_, virtual context
+ {
+ typedef query_columns_type base;
+ // Depending on the ptr argument, generate query_columns or
+ // pointer_query_columns specialization. The latter is used
+ // for object pointers where we don't support nested pointers.
+ //
+ query_columns_type (bool ptr): ptr_ (ptr) {}
+
+ virtual void
+ traverse (type& c)
+ {
+ string const& type (c.fq_name ());
+
+ if (ptr_)
{
- instance<query_columns> t;
- t->traverse (c);
+ os << "template <const char* table>" << endl
+ << "struct pointer_query_columns< " << type << ", table >";
+
+ // If we don't have pointers (in the whole hierarchy), then
+ // pointer_query_columns and query_columns are the same.
+ //
+ if (!has_a (c, test_pointer))
+ {
+ os << ":" << endl
+ << " query_columns< " << type << ", table >"
+ << "{"
+ << "};";
+ }
+ else
+ {
+ {
+ instance<query_columns_bases> b (ptr_);
+ traversal::inherits i (*b);
+ inherits (c, i);
+ }
+
+ os << "{";
+
+ {
+ instance<query_columns_base_aliases> b (ptr_);
+ traversal::inherits i (*b);
+ inherits (c, i);
+ }
+
+ {
+ instance<query_columns> t (ptr_);
+ t->traverse (c);
+ }
+
+ os << "};";
+
+ {
+ instance<query_columns> t (ptr_, c);
+ t->traverse (c);
+ }
+ }
}
+ else
+ {
+ bool has_ptr (has_a (c, test_pointer | exclude_base));
- os << "};";
+ if (has_ptr)
+ {
+ os << "template <>" << endl
+ << "struct query_columns_base< " << type << " >"
+ << "{";
+
+ instance<query_columns_base> t;
+ t->traverse (c);
+
+ os << "};";
+ }
+
+ os << "template <const char* table>" << endl
+ << "struct query_columns< " << type << ", table >";
+
+ if (has_ptr)
+ os << ":" << endl
+ << " query_columns_base< " << type << " >";
+
+ {
+ instance<query_columns_bases> b (ptr_, !has_ptr);
+ traversal::inherits i (*b);
+ inherits (c, i);
+ }
+
+ os << "{";
+
+ {
+ instance<query_columns_base_aliases> b (ptr_);
+ traversal::inherits i (*b);
+ inherits (c, i);
+ }
+
+ {
+ instance<query_columns> t (ptr_);
+ t->traverse (c);
+ }
+
+ os << "};";
+
+ {
+ instance<query_columns> t (ptr_, c);
+ t->traverse (c);
+ }
+ }
}
+
+ public:
+ bool ptr_;
};
// Member-specific traits types for container members.
@@ -368,9 +490,9 @@ namespace relational
// Statements.
//
- os << "static const char* const insert_one_statement;"
- << "static const char* const select_all_statement;"
- << "static const char* const delete_all_statement;"
+ os << "static const char insert_one_statement[];"
+ << "static const char select_all_statement[];"
+ << "static const char delete_all_statement[];"
<< endl;
}
@@ -732,18 +854,26 @@ namespace relational
semantics::class_& c_;
};
+ // First pass over objects, views, and composites. Some code must be
+ // split into two parts to deal with yet undefined types.
//
- //
- struct class_: traversal::class_, virtual context
+ struct class1: traversal::class_, virtual context
{
- typedef class_ base;
+ typedef class1 base;
- class_ (): id_image_member_ ("id_") {}
+ class1 ()
+ : id_image_member_ ("id_"),
+ query_columns_type_ (false),
+ pointer_query_columns_type_ (true)
+ {
+ }
- class_ (class_ const&)
+ class1 (class_ const&)
: root_context (), //@@ -Wextra
context (),
- id_image_member_ ("id_")
+ id_image_member_ ("id_"),
+ query_columns_type_ (false),
+ pointer_query_columns_type_ (true)
{
}
@@ -774,7 +904,6 @@ 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));
@@ -784,12 +913,33 @@ namespace relational
os << "// " << c.name () << endl
<< "//" << endl;
+ // class_traits
+ //
os << "template <>" << endl
<< "struct class_traits< " << type << " >"
<< "{"
<< "static const class_kind kind = class_object;"
<< "};";
+ // pointer_query_columns & query_columns
+ //
+ if (options.generate_query ())
+ {
+ // If we don't have object pointers, then also generate
+ // query_columns (in this case pointer_query_columns and
+ // query_columns are the same and the former inherits from
+ // the latter). Otherwise we have to postpone query_columns
+ // generation until the second pass to deal with forward-
+ // declared objects.
+ //
+ if (!has_a (c, test_pointer))
+ query_columns_type_->traverse (c);
+
+ pointer_query_columns_type_->traverse (c);
+ }
+
+ // object_traits
+ //
os << "template <>" << endl
<< "class access::object_traits< " << type << " >"
<< "{"
@@ -837,17 +987,6 @@ namespace relational
image_type_->traverse (c);
//
- // Query (abstract and concrete).
- //
-
- if (options.generate_query ())
- {
- // query_columns
- //
- query_type_->traverse (c);
- }
-
- //
// Containers (abstract and concrete).
//
@@ -919,7 +1058,7 @@ namespace relational
//
// The rest only applies to concrete objects.
//
- if (abst)
+ if (abstract (c))
{
object_public_extra_post (c);
os << "};";
@@ -939,12 +1078,7 @@ namespace relational
// query_type
//
- os << "struct query_type: query_base_type, query_columns"
- << "{"
- << "query_type ();"
- << "query_type (const std::string&);"
- << "query_type (const query_base_type&);"
- << "};";
+ os << "struct query_type;";
}
//
@@ -966,17 +1100,17 @@ namespace relational
// 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;";
+ os << "static const char persist_statement[];"
+ << "static const char find_statement[];"
+ << "static const char update_statement[];"
+ << "static const char erase_statement[];";
if (options.generate_query ())
{
- os << "static const char* const query_clause;"
- << "static const char* const erase_query_clause;"
+ os << "static const char query_clause[];"
+ << "static const char erase_query_clause[];"
<< endl
- << "static const char* const table_name;";
+ << "static const char table_name[];";
}
os << endl;
@@ -1184,7 +1318,7 @@ namespace relational
// Statements.
//
- os << "static const char* const query_statement;"
+ os << "static const char query_statement[];"
<< endl;
//
@@ -1272,8 +1406,87 @@ namespace relational
private:
instance<image_type> image_type_;
- instance<query_type> query_type_;
instance<image_member> id_image_member_;
+
+ instance<query_columns_type> query_columns_type_;
+ instance<query_columns_type> pointer_query_columns_type_;
+ };
+
+ // Second pass over objects, views, and composites.
+ //
+ struct class2: traversal::class_, virtual context
+ {
+ typedef class2 base;
+
+ class2 (): query_columns_type_ (false) {}
+
+ class2 (class_ const&)
+ : root_context (), //@@ -Wextra
+ context (),
+ query_columns_type_ (false)
+ {
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ if (c.file () != unit.file ())
+ return;
+
+ if (object (c))
+ traverse_object (c);
+ else if (view (c))
+ traverse_view (c);
+ else if (composite (c))
+ traverse_composite (c);
+ }
+
+ virtual void
+ traverse_object (type& c)
+ {
+ bool abst (abstract (c));
+ string const& type (c.fq_name ());
+
+ os << "// " << c.name () << endl
+ << "//" << endl;
+
+ if (options.generate_query ())
+ {
+ // query_columns
+ //
+ // If we don't have any pointers, then query_columns is generated
+ // in pass 1 (see the comment in class1 for details).
+ //
+ if (has_a (c, test_pointer))
+ query_columns_type_->traverse (c);
+
+ // query_type
+ //
+ if (!abst)
+ os << "struct access::object_traits< " << type << " >::" <<
+ "query_type:" << endl
+ << " query_base_type," << endl
+ << " query_columns< " << type << ", table_name >"
+ << "{"
+ << "query_type ();"
+ << "query_type (const std::string&);"
+ << "query_type (const query_base_type&);"
+ << "};";
+ }
+ }
+
+ virtual void
+ traverse_view (type&)
+ {
+ }
+
+ virtual void
+ traverse_composite (type&)
+ {
+ }
+
+ private:
+ instance<query_columns_type> query_columns_type_;
};
struct include: virtual context
diff --git a/odb/relational/pgsql/header.cxx b/odb/relational/pgsql/header.cxx
index 8a606bd..4043809 100644
--- a/odb/relational/pgsql/header.cxx
+++ b/odb/relational/pgsql/header.cxx
@@ -16,9 +16,9 @@ namespace relational
{
namespace relational = relational::header;
- struct class_: relational::class_
+ struct class1: relational::class1
{
- class_ (base const& x): base (x) {}
+ class1 (base const& x): base (x) {}
virtual void
object_public_extra_post (type& c)
@@ -28,16 +28,16 @@ namespace relational
// Statement names.
//
- os << "static const char* const persist_statement_name;"
- << "static const char* const find_statement_name;"
- << "static const char* const update_statement_name;"
- << "static const char* const erase_statement_name;";
+ os << "static const char persist_statement_name[];"
+ << "static const char find_statement_name[];"
+ << "static const char update_statement_name[];"
+ << "static const char erase_statement_name[];";
// Query statement name.
//
if (options.generate_query ())
- os << "static const char* const query_statement_name;"
- << "static const char* const erase_query_statement_name;";
+ os << "static const char query_statement_name[];"
+ << "static const char erase_query_statement_name[];";
os << endl;
@@ -56,11 +56,11 @@ namespace relational
{
// Statement names.
//
- os << "static const char* const query_statement_name;"
+ os << "static const char query_statement_name[];"
<< endl;
}
};
- entry<class_> class_entry_;
+ entry<class1> class1_entry_;
struct container_traits: relational::container_traits, context
{
@@ -74,9 +74,9 @@ namespace relational
// Container statement names.
//
- os << "static const char* const select_all_name;"
- << "static const char* const insert_one_name;"
- << "static const char* const delete_all_name;"
+ os << "static const char select_all_name[];"
+ << "static const char insert_one_name[];"
+ << "static const char delete_all_name[];"
<< endl;
// Container statement types.
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
index f020c5a..28d04e6 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/relational/pgsql/source.cxx
@@ -891,19 +891,19 @@ namespace relational
string const& n (c.fq_name ());
string traits ("access::object_traits< " + n + " >::");
string const& fn (flat_name (n));
- string name_decl ("const char* const " + traits);
+ string name_decl ("const char " + traits);
os << name_decl << endl
- << "persist_statement_name = " << strlit (fn + "_persist") << ";"
+ << "persist_statement_name[] = " << strlit (fn + "_persist") << ";"
<< endl
<< name_decl << endl
- << "find_statement_name = " << strlit (fn + "_find") << ";"
+ << "find_statement_name[] = " << strlit (fn + "_find") << ";"
<< endl
<< name_decl << endl
- << "update_statement_name = " << strlit (fn + "_update") << ";"
+ << "update_statement_name[] = " << strlit (fn + "_update") << ";"
<< endl
<< name_decl << endl
- << "erase_statement_name = " << strlit (fn + "_erase") << ";"
+ << "erase_statement_name[] = " << strlit (fn + "_erase") << ";"
<< endl;
// Query statement name.
@@ -911,10 +911,10 @@ namespace relational
if (options.generate_query ())
{
os << name_decl << endl
- << "query_statement_name = " << strlit (fn + "_query") << ";"
+ << "query_statement_name[] = " << strlit (fn + "_query") << ";"
<< endl
<< name_decl << endl
- << "erase_query_statement_name = " <<
+ << "erase_query_statement_name[] = " <<
strlit (fn + "_erase_query") << ";"
<< endl;
}
@@ -984,10 +984,10 @@ namespace relational
string const& n (c.fq_name ());
string traits ("access::view_traits< " + n + " >::");
string const& fn (flat_name (n));
- string name_decl ("const char* const " + traits);
+ string name_decl ("const char " + traits);
os << name_decl << endl
- << "query_statement_name = " << strlit (fn + "_query") << ";"
+ << "query_statement_name[] = " << strlit (fn + "_query") << ";"
<< endl;
}
@@ -996,7 +996,7 @@ namespace relational
{
os << "sts.connection ()," << endl
<< "query_statement_name," << endl
- << "query_clause + q.clause (table_name)," << endl
+ << "query_clause + q.clause ()," << endl
<< "q.parameter_types ()," << endl
<< "q.parameter_count ()," << endl
<< "q.parameters_binding ()," << endl
@@ -1008,7 +1008,7 @@ namespace relational
{
os << "conn," << endl
<< "erase_query_statement_name," << endl
- << "erase_query_clause + q.clause (table_name)," << endl
+ << "erase_query_clause + q.clause ()," << endl
<< "q.parameter_types ()," << endl
<< "q.parameter_count ()," << endl
<< "q.parameters_binding ()";
@@ -1019,7 +1019,7 @@ namespace relational
{
os << "sts.connection ()," << endl
<< "query_statement_name," << endl
- << "query_statement + q.clause (\"\")," << endl
+ << "query_statement + q.clause ()," << endl
<< "q.parameter_types ()," << endl
<< "q.parameter_count ()," << endl
<< "q.parameters_binding ()," << endl
@@ -1048,7 +1048,7 @@ namespace relational
// Statment names.
//
- string stmt_decl ("const char* const " + scope + "::");
+ string stmt_decl ("const char " + scope + "::");
// Prefix top-object name to avoid conflicts with inherited
// member statement names.
@@ -1056,15 +1056,15 @@ namespace relational
string stmt_prefix (top_object->fq_name () + m.fq_name ());
os << stmt_decl << endl
- << "select_all_name = " <<
+ << "select_all_name[] = " <<
strlit (stmt_prefix + "_select_all") << ";"
<< endl
<< stmt_decl << endl
- << "insert_one_name = " <<
+ << "insert_one_name[] = " <<
strlit (stmt_prefix + "_insert_one") << ";"
<< endl
<< stmt_decl << endl
- << "delete_all_name = " <<
+ << "delete_all_name[] = " <<
strlit (stmt_prefix + "_delete_all") << ";"
<< endl;
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index a3ef5de..f83ad24 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -91,7 +91,8 @@ namespace relational
if (container_wrapper (im->type ()))
{
// This container is a direct member of the class so the table
- // prefix is just the class table name.
+ // prefix is just the class table name. We don't assign join
+ // aliases for container tables so use the actual table name.
//
column (
*im, "id",
@@ -104,8 +105,12 @@ namespace relational
else
{
semantics::data_member& id (*id_member (*c));
+
+ // Use the join alias (column name) instead of the actual
+ // table name unless we are handling a container.
+ //
column (id, "",
- table_name_.empty () ? table_name_ : table_qname (*c),
+ table_name_.empty () ? table_name_ : quote_id (name),
column_qname (id));
}
}
@@ -162,7 +167,7 @@ namespace relational
{
typedef object_joins base;
- //@@ context::{cur,top}_object Might have to be created every time.
+ //@@ context::{cur,top}_object; might have to be created every time.
//
object_joins (semantics::class_& scope, bool query)
: query_ (query),
@@ -188,38 +193,25 @@ namespace relational
string line (" LEFT JOIN ");
line += i->table;
- // If this is a self-join, alias it as '_' to resolve any
- // ambiguities.
- //
- if (i->table == table_)
- line += " AS _";
+ if (!i->alias.empty ())
+ line += " AS " + i->alias;
line += " ON ";
-
- for (conditions::iterator b (i->cond.begin ()), j (b);
- j != i->cond.end (); ++j)
- {
- if (j != b)
- line += " OR ";
-
- line += *j;
- }
+ line += i->cond;
os << strlit (line) << endl;
}
}
virtual bool
- traverse_column (semantics::data_member& m,
- string const& col_name,
- bool)
+ traverse_column (semantics::data_member& m, string const& column, bool)
{
semantics::class_* c (object_pointer (m.type ()));
if (c == 0)
- return true;
+ return false;
- string t, dt;
+ string t, a, dt, da;
std::ostringstream cond, dcond; // @@ diversion?
if (semantics::data_member* im = inverse (m))
@@ -243,33 +235,20 @@ namespace relational
if (query_)
{
dt = quote_id (ct);
- string const& id (column_qname (*im, "id", "object_id"));
+ da = quote_id (column);
- // If this is a self-join, use the '_' alias instead of the
- // table name.
- //
- if (dt == table_)
- dcond << "_";
- else
- dcond << dt;
+ string const& id (column_qname (*im, "id", "object_id"));
- dcond << '.' << column_qname (*id_member (*c)) << " = " <<
+ dcond << da << '.' << column_qname (*id_member (*c)) << " = " <<
t << '.' << id;
}
}
else
{
t = table_qname (*c);
+ a = quote_id (column);
- // If this is a self-join, use the '_' alias instead of the
- // table name.
- //
- if (t == table_)
- cond << "_";
- else
- cond << t;
-
- cond << '.' << column_qname (*im) << " = " <<
+ cond << a << '.' << column_qname (*im) << " = " <<
table_ << "." << column_qname (id_);
}
}
@@ -279,61 +258,29 @@ namespace relational
// in the WHERE clause.
//
t = table_qname (*c);
+ a = quote_id (column);
- // If this is a self-join, use the '_' alias instead of the
- // table name.
- //
- if (t == table_)
- cond << "_";
- else
- cond << t;
-
- cond << '.' << column_qname (*id_member (*c)) << " = " <<
- table_ << "." << quote_id (col_name);
+ cond << a << '.' << column_qname (*id_member (*c)) << " = " <<
+ table_ << "." << quote_id (column);
}
if (!t.empty ())
{
- size_t i;
- table_map::iterator it (table_map_.find (t));
-
- if (it != table_map_.end ())
- i = it->second;
- else
- {
- i = joins_.size ();
- joins_.push_back (join ());
- table_map_[t] = i;
- }
-
- joins_[i].table = t;
- joins_[i].cond.insert (cond.str ());
+ joins_.push_back (join ());
+ joins_.back ().table = t;
+ joins_.back ().alias = a;
+ joins_.back ().cond = cond.str ();
}
+ // Add dependent join (i.e., an object table join via the
+ // container table).
+ //
if (!dt.empty ())
{
- // Add dependent join. If one already exists, move it to the
- // bottom.
- //
- size_t i;
- table_map::iterator it (table_map_.find (dt));
-
- if (it != table_map_.end ())
- {
- i = joins_.size ();
- joins_.push_back (join ());
- joins_[it->second].swap (joins_.back ());
- it->second = i;
- }
- else
- {
- i = joins_.size ();
- joins_.push_back (join ());
- table_map_[dt] = i;
- }
-
- joins_[i].table = dt;
- joins_[i].cond.insert (dcond.str ());
+ joins_.push_back (join ());
+ joins_.back ().table = dt;
+ joins_.back ().alias = da;
+ joins_.back ().cond = dcond.str ();
}
return true;
@@ -341,29 +288,19 @@ namespace relational
private:
bool query_;
- string table_; //@@ No longer used because of the _ alias.
+ string table_;
semantics::data_member& id_;
- typedef std::set<string> conditions;
-
struct join
{
string table;
- conditions cond;
-
- void
- swap (join& o)
- {
- table.swap (o.table);
- cond.swap (o.cond);
- }
+ string alias;
+ string cond;
};
typedef std::vector<join> joins;
- typedef std::map<string, size_t> table_map;
joins joins_;
- table_map table_map_;
};
//
@@ -715,8 +652,8 @@ namespace relational
// select_all_statement
//
- os << "const char* const " << scope <<
- "::select_all_statement =" << endl;
+ os << "const char " << scope <<
+ "::select_all_statement[] =" << endl;
if (inverse)
{
@@ -830,8 +767,8 @@ namespace relational
// insert_one_statement
//
- os << "const char* const " << scope <<
- "::insert_one_statement =" << endl;
+ os << "const char " << scope <<
+ "::insert_one_statement[] =" << endl;
if (inverse)
os << strlit ("") << ";"
@@ -901,8 +838,8 @@ namespace relational
// delete_all_statement
//
- os << "const char* const " << scope <<
- "::delete_all_statement =" << endl;
+ os << "const char " << scope <<
+ "::delete_all_statement[] =" << endl;
if (inverse)
os << strlit ("") << ";"
@@ -1935,7 +1872,7 @@ namespace relational
object_query_statement_ctor_args (type&)
{
os << "sts.connection ()," << endl
- << "query_clause + q.clause (table_name)," << endl
+ << "query_clause + q.clause ()," << endl
<< "q.parameters_binding ()," << endl
<< "imb";
}
@@ -1944,7 +1881,7 @@ namespace relational
object_erase_query_statement_ctor_args (type&)
{
os << "conn," << endl
- << "erase_query_clause + q.clause (table_name)," << endl
+ << "erase_query_clause + q.clause ()," << endl
<< "q.parameters_binding ()";
}
@@ -1956,6 +1893,7 @@ namespace relational
string traits ("access::object_traits< " + type + " >");
bool grow (context::grow (c));
+ bool has_ptr (has_a (c, test_pointer));
semantics::data_member* id (id_member (c));
bool auto_id (id ? id->count ("auto") : false);
@@ -1974,8 +1912,13 @@ namespace relational
if (options.generate_query ())
{
- instance<query_columns> t (c);
- t->traverse (c);
+ // query_columns_base
+ //
+ if (has_ptr)
+ {
+ instance<query_columns_base> t (c);
+ t->traverse (c);
+ }
}
//
@@ -2147,7 +2090,7 @@ namespace relational
// persist_statement
//
{
- os << "const char* const " << traits << "::persist_statement " <<
+ os << "const char " << traits << "::persist_statement[] " <<
"=" << endl
<< strlit ("INSERT INTO " + table + " (") << endl;
@@ -2165,7 +2108,7 @@ namespace relational
// find_statement
//
{
- os << "const char* const " << traits << "::find_statement =" << endl
+ os << "const char " << traits << "::find_statement[] =" << endl
<< strlit ("SELECT ") << endl;
instance<object_columns> t (table, true);
@@ -2187,7 +2130,7 @@ namespace relational
// update_statement
//
{
- os << "const char* const " << traits << "::update_statement " <<
+ os << "const char " << traits << "::update_statement[] " <<
"=" << endl
<< strlit ("UPDATE " + table + " SET ") << endl;
@@ -2203,7 +2146,7 @@ namespace relational
//
{
instance<query_parameters> qp;
- os << "const char* const " << traits << "::erase_statement =" << endl
+ os << "const char " << traits << "::erase_statement[] =" << endl
<< strlit ("DELETE FROM " + table) << endl
<< strlit (" WHERE " + id_col + "=" + qp->next ()) << ";"
<< endl;
@@ -2220,7 +2163,7 @@ namespace relational
// We only need DISTINCT if there are joins (object pointers)
// and can optimize it out otherwise.
//
- os << "const char* const " << traits << "::query_clause =" << endl
+ os << "const char " << traits << "::query_clause[] =" << endl
<< strlit (oj->count () ? "SELECT DISTINCT " : "SELECT ") << endl;
{
@@ -2235,7 +2178,7 @@ namespace relational
// erase_query_clause
//
- os << "const char* const " << traits << "::erase_query_clause =" << endl
+ os << "const char " << traits << "::erase_query_clause[] =" << endl
<< strlit ("DELETE FROM " + table) << endl;
// DELETE JOIN:
@@ -2251,8 +2194,8 @@ namespace relational
// table_name
//
- os << "const char* const " << traits << "::table_name =" << endl
- << strlit (table) << ";"
+ os << "const char " << traits << "::table_name[] =" << endl
+ << strlit (table_name (c)) << ";" // Use unquoted name.
<< endl;
}
@@ -2849,7 +2792,7 @@ namespace relational
view_query_statement_ctor_args (type&)
{
os << "sts.connection ()," << endl
- << "query_statement + q.clause (\"\")," << endl
+ << "query_statement + q.clause ()," << endl
<< "q.parameters_binding ()," << endl
<< "imb";
}
@@ -2917,7 +2860,7 @@ namespace relational
// query_statement
//
- os << "const char* const " << traits << "::query_statement =" << endl
+ os << "const char " << traits << "::query_statement[] =" << endl
<< strlit (c.get<string> ("query")) << endl
<< strlit (" ") << ";" << endl
<< endl;