From a7bd7367e246ec5b6bb2e2f018a05173ff7e6301 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 27 Sep 2011 11:20:31 +0200 Subject: Add support for associating tables with views --- odb/context.hxx | 16 +++-- odb/pragma.cxx | 91 ++++++++++++++++++++++++----- odb/pragma.hxx | 6 +- odb/relational/header.hxx | 26 ++++++--- odb/relational/inline.hxx | 4 +- odb/relational/processor.cxx | 52 +++++++++++++---- odb/relational/source.cxx | 4 +- odb/relational/source.hxx | 136 +++++++++++++++++++++++++++++++++---------- 8 files changed, 261 insertions(+), 74 deletions(-) diff --git a/odb/context.hxx b/odb/context.hxx index 550b64e..f91568a 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -113,7 +113,7 @@ struct default_value tree node; }; -// +// Object or table associated with the view. // struct view_object { @@ -122,21 +122,29 @@ struct view_object std::string name () const { - return alias.empty () ? object->name () : alias; + if (!alias.empty ()) + return alias; + + return kind == object ? obj->name () : orig_name; } - tree node; + enum kind_type { object, table }; + + kind_type kind; + tree node; // Tree node if kind is object. std::string orig_name; // Original name as specified in the pragma. std::string alias; tree scope; location_t loc; - semantics::class_* object; + semantics::class_* obj; cxx_tokens cond; // Join condition tokens. }; typedef std::vector view_objects; +// The view_alias_map does not contain entries for tables. +// typedef std::map view_alias_map; typedef std::map view_object_map; diff --git a/odb/pragma.cxx b/odb/pragma.cxx index 2fb6d27..56cf7c9 100644 --- a/odb/pragma.cxx +++ b/odb/pragma.cxx @@ -443,6 +443,22 @@ check_spec_decl_type (tree d, } static void +add_pragma (pragma const& prag, tree decl) +{ + if (decl) + decl_pragmas_[decl].insert (prag); + else + { + tree scope (current_scope ()); + + if (!CLASS_TYPE_P (scope)) + scope = global_namespace; + + loc_pragmas_[scope].push_back (prag); + } +} + +static void handle_pragma (cpp_reader* reader, string const& p, tree decl, @@ -459,6 +475,7 @@ handle_pragma (cpp_reader* reader, if (p == "table") { // table ("") + // table ("" [= ""] [: ""] (view only) // // Make sure we've got the correct declaration type. @@ -480,14 +497,69 @@ handle_pragma (cpp_reader* reader, return; } - val = string (TREE_STRING_POINTER (t)); + // The table specifier is used for both objects and views. In case + // of an object, the context values is just a string. In case of a + // view, the context value is a view_object entry. The problem is + // that at this stage we don't know whether we are dealing with an + // object or a view. To resolve this in a somewhat hackish way, we + // are going to create both a string and a view_object entry. + // + view_object vo; + vo.kind = view_object::table; + vo.orig_name = TREE_STRING_POINTER (t); - if (pragma_lex (&t) != CPP_CLOSE_PAREN) + tt = pragma_lex (&t); + + if (tt == CPP_EQ) + { + // We have an alias. + // + if (pragma_lex (&t) != CPP_STRING) + { + error () + << "table alias expected after '=' in db pragma " << p << endl; + return; + } + + vo.alias = TREE_STRING_POINTER (t); + tt = pragma_lex (&t); + } + + if (tt == CPP_COLON) + { + // We have a condition. + + tt = pragma_lex (&t); + + if (!parse_expression (t, tt, vo.cond, p)) + return; // Diagnostics has already been issued. + + if (vo.cond.empty ()) + { + error () + << "join condition expected after ':' in db pragma " << p << endl; + return; + } + } + + if (tt != CPP_CLOSE_PAREN) { error () << "')' expected at the end of db pragma " << p << endl; return; } + // Add the "table" pragma. + // + if (vo.alias.empty () && vo.cond.empty ()) + add_pragma ( + pragma (p, name, vo.orig_name, loc, &check_spec_decl_type, 0), decl); + + vo.scope = current_scope (); + vo.loc = loc; + val = vo; + name = "objects"; + adder = &accumulate; + tt = pragma_lex (&t); } else if (p == "pointer") @@ -723,6 +795,7 @@ handle_pragma (cpp_reader* reader, } view_object vo; + vo.kind = view_object::object; vo.node = resolve_scoped_name (t, tt, vo.orig_name, true, p); if (vo.node == 0) @@ -1360,19 +1433,7 @@ handle_pragma (cpp_reader* reader, // Record this pragma. // - pragma prag (p, name, val, loc, &check_spec_decl_type, adder); - - if (decl) - decl_pragmas_[decl].insert (prag); - else - { - tree scope (current_scope ()); - - if (!CLASS_TYPE_P (scope)) - scope = global_namespace; - - loc_pragmas_[scope].push_back (prag); - } + add_pragma (pragma (p, name, val, loc, &check_spec_decl_type, adder), decl); // See if there are any more pragmas. // diff --git a/odb/pragma.hxx b/odb/pragma.hxx index ba4aab8..0b09b43 100644 --- a/odb/pragma.hxx +++ b/odb/pragma.hxx @@ -52,10 +52,10 @@ struct pragma operator< (pragma const& y) const { if (add == 0) - return pragma_name < y.pragma_name; + return context_name < y.context_name; else - return pragma_name < y.pragma_name || - (pragma_name == y.pragma_name && loc < y.loc); + return context_name < y.context_name || + (context_name == y.context_name && loc < y.loc); } std::string pragma_name; // Actual pragma name for diagnostics. diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index 50a40b2..1380c49 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -1258,11 +1258,13 @@ namespace relational // query_type // - if (c.count ("objects")) + size_t obj_count (c.get ("object-count")); + + if (obj_count != 0) { view_objects& objs (c.get ("objects")); - if (objs.size () > 1) + if (obj_count > 1) { os << "struct query_columns" << "{"; @@ -1271,8 +1273,11 @@ namespace relational i < objs.end (); ++i) { + if (i->kind != view_object::object) + continue; // Skip tables. + bool alias (!i->alias.empty ()); - semantics::class_& o (*i->object); + semantics::class_& o (*i->obj); string const& name (alias ? i->alias : o.name ()); string const& type (o.fq_name ()); @@ -1306,13 +1311,20 @@ namespace relational // For a single object view we generate a shortcut without // an intermediate typedef. // - view_object const& vo (objs[0]); + view_object const* vo (0); + for (view_objects::const_iterator i (objs.begin ()); + vo == 0 && i < objs.end (); + ++i) + { + if (i->kind == view_object::object) + vo = &*i; + } - bool alias (!vo.alias.empty ()); - semantics::class_& o (*vo.object); + bool alias (!vo->alias.empty ()); + semantics::class_& o (*vo->obj); string const& type (o.fq_name ()); - if (alias && vo.alias != table_name (o)) + if (alias && vo->alias != table_name (o)) os << "static const char query_alias[];" << endl << "struct query_type:" << endl diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx index 9abc86f..78d81bf 100644 --- a/odb/relational/inline.hxx +++ b/odb/relational/inline.hxx @@ -274,7 +274,9 @@ namespace relational // query_type // - if (c.count ("objects")) + size_t obj_count (c.get ("object-count")); + + if (obj_count != 0) { os << "inline" << endl << traits << "::query_type::" << endl diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx index 82852f0..83adb39 100644 --- a/odb/relational/processor.cxx +++ b/odb/relational/processor.cxx @@ -1169,7 +1169,7 @@ namespace relational if (j != amap_.end ()) { i->table = j->first; - obj = j->second->object; + obj = j->second->obj; // Skip '::'. // @@ -1215,7 +1215,7 @@ namespace relational throw operation_failed (); } - obj = j->second->object; + obj = j->second->obj; i->table = table_name (*obj); } @@ -1308,7 +1308,10 @@ namespace relational member_resolver resolver (exact_members, pub_members, m); for (view_objects::iterator i (objs.begin ()); i != objs.end (); ++i) - resolver.traverse (*i); + { + if (i->kind == view_object::object) + resolver.traverse (*i); + } assoc_members& members ( !exact_members.empty () ? exact_members : pub_members); @@ -1362,7 +1365,7 @@ namespace relational ep.kind = column_expr_part::reference; ep.table = am.vo->alias.empty () - ? table_name (*am.vo->object) + ? table_name (*am.vo->obj) : am.vo->alias; ep.member_path.push_back (am.m); @@ -1395,7 +1398,7 @@ namespace relational traverse (view_object& vo) { member_.vo_ = &vo; - traverse (*vo.object); + traverse (*vo.obj); } virtual void @@ -1636,6 +1639,9 @@ namespace relational view_alias_map& amap (c.set ("alias-map", view_alias_map ())); view_object_map& omap (c.set ("object-map", view_object_map ())); + size_t& obj_count (c.set ("object-count", size_t (0))); + size_t& tbl_count (c.set ("table-count", size_t (0))); + if (has_o) { using semantics::class_; @@ -1644,6 +1650,25 @@ namespace relational for (view_objects::iterator i (objs.begin ()); i != objs.end (); ++i) { + if (i->kind != view_object::object) + { + // Make sure we have join conditions for tables unless it + // is the first entry. + // + if (i != objs.begin () && i->cond.empty ()) + { + error (i->loc) + << "missing join condition in db pragma table" << endl; + + throw operation_failed (); + } + + tbl_count++; + continue; + } + else + obj_count++; + tree n (TYPE_MAIN_VARIANT (i->node)); if (TREE_CODE (n) != RECORD_TYPE) @@ -1669,7 +1694,7 @@ namespace relational throw operation_failed (); } - i->object = &o; + i->obj = &o; if (i->alias.empty ()) { @@ -1716,6 +1741,9 @@ namespace relational // for (view_objects::iterator j (objs.begin ()); j != i; ++j) { + if (j->kind != view_object::object) + continue; // Skip tables. + // First see if any of the objects that were specified // prior to this object point to it. // @@ -1785,7 +1813,7 @@ namespace relational relationship const& r (rs.back ()); string name (r.pointer->alias.empty () - ? r.pointer->object->fq_name () + ? r.pointer->obj->fq_name () : r.pointer->alias); name += "::"; name += r.name; @@ -1832,7 +1860,7 @@ namespace relational traverse (view_object& pointer) { pointer_ = &pointer; - object_members_base::traverse (*pointer.object); + object_members_base::traverse (*pointer.obj); } virtual void @@ -1849,10 +1877,10 @@ namespace relational // Ignore self-pointers if requested. // - if (!self_pointer_ && pointer_->object == c) + if (!self_pointer_ && pointer_->obj == c) return; - if (pointee_.object == c) + if (pointee_.obj == c) { relationships_.push_back (relationship ()); relationships_.back ().member = &m; @@ -1874,10 +1902,10 @@ namespace relational // Ignore self-pointers if requested. // - if (!self_pointer_ && pointer_->object == c) + if (!self_pointer_ && pointer_->obj == c) return; - if (pointee_.object == c) + if (pointee_.obj == c) { relationships_.push_back (relationship ()); relationships_.back ().member = &m; diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index 6b364cf..5dfc15a 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -138,7 +138,7 @@ namespace relational tt = lex.next (t); decl = lookup::resolve_scoped_name ( - t, tt, ptt, lex, vo->object->tree_node (), name, false); + t, tt, ptt, lex, vo->obj->tree_node (), name, false); } } @@ -172,7 +172,7 @@ namespace relational if (multi_obj) { r += "::"; - r += vo->object->name (); + r += vo->obj->name (); } } diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index 3474f15..fbe9b1c 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -2959,17 +2959,22 @@ namespace relational // query_type // - if (c.count ("objects")) + size_t obj_count (c.get ("object-count")); + + if (obj_count != 0) { view_objects& objs (c.get ("objects")); - if (objs.size () > 1) + if (obj_count > 1) { for (view_objects::const_iterator i (objs.begin ()); i < objs.end (); ++i) { - if (!i->alias.empty () && i->alias != table_name (*i->object)) + if (i->kind != view_object::object) + continue; // Skip tables. + + if (!i->alias.empty () && i->alias != table_name (*i->obj)) os << "const char " << traits << "::query_columns::" << endl << i->alias << "_alias_[] = " << strlit (i->alias) << ";" << endl; @@ -2980,11 +2985,18 @@ namespace relational // For a single object view we generate a shortcut without // an intermediate typedef. // - view_object const& vo (objs[0]); + view_object const* vo (0); + for (view_objects::const_iterator i (objs.begin ()); + vo == 0 && i < objs.end (); + ++i) + { + if (i->kind == view_object::object) + vo = &*i; + } - if (!vo.alias.empty () && vo.alias != table_name (*vo.object)) + if (!vo->alias.empty () && vo->alias != table_name (*vo->obj)) os << "const char " << traits << "::" << endl - << "query_alias[] = " << strlit (vo.alias) << ";" + << "query_alias[] = " << strlit (vo->alias) << ";" << endl; } } @@ -3119,14 +3131,78 @@ namespace relational i != objs.end (); ++i) { + bool first (i == objs.begin ()); string l; + // + // Tables. + // + + if (i->kind == view_object::table) + { + if (first) + { + l = "FROM "; + l += quote_id (i->orig_name); + + if (!i->alias.empty ()) + { + l += " AS "; + l += quote_id (i->alias); + } + + os << "r += " << strlit (l) << ";" + << endl; + + continue; + } + + l = "LEFT JOIN "; + l += quote_id (i->orig_name); + + if (!i->alias.empty ()) + { + l += " AS "; + l += quote_id (i->alias); + } + + expression e ( + translate_expression ( + c, i->cond, i->scope, i->loc, "table")); + + if (e.kind != expression::literal) + { + error (i->loc) + << "invalid join condition in db pragma table" << endl; + + throw operation_failed (); + } + + l += " ON"; + + os << "r += " << strlit (l) << ";" + // Output the pragma location for easier error tracking. + // + << "// From " << + location_file (i->loc).leaf () << ":" << + location_line (i->loc) << ":" << + location_column (i->loc) << endl + << "r += " << e.value << ";" + << endl; + + continue; + } + + // + // Objects. + // + // First object. // - if (i == objs.begin ()) + if (first) { l = "FROM "; - l += table_qname (*i->object); + l += table_qname (*i->obj); if (!i->alias.empty ()) { @@ -3149,7 +3225,7 @@ namespace relational if (e.kind == expression::literal) { l = "LEFT JOIN "; - l += table_qname (*i->object); + l += table_qname (*i->obj); if (!i->alias.empty ()) { @@ -3198,7 +3274,7 @@ namespace relational // pointer to ourselves is always assumed to point // to this association. // - if (i->object == c) + if (i->obj == c) vo = &*i; else { @@ -3208,7 +3284,7 @@ namespace relational j != i; ++j) { - if (j->object != c) + if (j->obj != c) continue; if (vo == 0) @@ -3262,11 +3338,11 @@ namespace relational // Left and right-hand side table names. // string lt (e.vo->alias.empty () - ? table_name (*e.vo->object) + ? table_name (*e.vo->obj) : e.vo->alias); string rt (vo->alias.empty () - ? table_name (*vo->object) + ? table_name (*vo->obj) : vo->alias); // First join the container table if necessary. @@ -3288,11 +3364,11 @@ namespace relational // function would have to return a member path instead // of just a single member. // - table_prefix tp (table_name (*vo->object) + "_", 1); + table_prefix tp (table_name (*vo->obj) + "_", 1); ct = table_qname (*im, tp); } else - ct = table_qname (*e.vo->object, e.member_path); + ct = table_qname (*e.vo->obj, e.member_path); } if (cont != 0) @@ -3309,7 +3385,7 @@ namespace relational // if (im != 0) { - if (i->object == c) + if (i->obj == c) { // container.value = pointer.id // @@ -3319,7 +3395,7 @@ namespace relational l += "="; l += quote_id (lt); l += '.'; - l += column_qname (*id_member (*e.vo->object)); + l += column_qname (*id_member (*e.vo->obj)); } else { @@ -3331,12 +3407,12 @@ namespace relational l += "="; l += quote_id (rt); l += '.'; - l += column_qname (*id_member (*vo->object)); + l += column_qname (*id_member (*vo->obj)); } } else { - if (i->object == c) + if (i->obj == c) { // container.id = pointer.id // @@ -3346,7 +3422,7 @@ namespace relational l += "="; l += quote_id (lt); l += '.'; - l += column_qname (*id_member (*e.vo->object)); + l += column_qname (*id_member (*e.vo->obj)); } else { @@ -3358,7 +3434,7 @@ namespace relational l += "="; l += quote_id (rt); l += '.'; - l += column_qname (*id_member (*vo->object)); + l += column_qname (*id_member (*vo->obj)); } } @@ -3366,7 +3442,7 @@ namespace relational } l = "LEFT JOIN "; - l += table_qname (*i->object); + l += table_qname (*i->obj); if (!i->alias.empty ()) { @@ -3381,7 +3457,7 @@ namespace relational { if (im != 0) { - if (i->object == c) + if (i->obj == c) { // container.id = pointed-to.id // @@ -3391,7 +3467,7 @@ namespace relational l += "="; l += quote_id (rt); l += '.'; - l += column_qname (*id_member (*vo->object)); + l += column_qname (*id_member (*vo->obj)); } else { @@ -3403,12 +3479,12 @@ namespace relational l += "="; l += quote_id (lt); l += '.'; - l += column_qname (*id_member (*e.vo->object)); + l += column_qname (*id_member (*e.vo->obj)); } } else { - if (i->object == c) + if (i->obj == c) { // container.value = pointed-to.id // @@ -3418,7 +3494,7 @@ namespace relational l += "="; l += quote_id (rt); l += '.'; - l += column_qname (*id_member (*vo->object)); + l += column_qname (*id_member (*vo->obj)); } else { @@ -3430,7 +3506,7 @@ namespace relational l += "="; l += quote_id (lt); l += '.'; - l += column_qname (*id_member (*e.vo->object)); + l += column_qname (*id_member (*e.vo->obj)); } } } @@ -3442,7 +3518,7 @@ namespace relational // l = quote_id (lt); l += '.'; - l += column_qname (*id_member (*e.vo->object)); + l += column_qname (*id_member (*e.vo->obj)); l += " = "; l += quote_id (rt); l += '.'; @@ -3458,7 +3534,7 @@ namespace relational l += " = "; l += quote_id (rt); l += '.'; - l += column_qname (*id_member (*vo->object)); + l += column_qname (*id_member (*vo->obj)); } } -- cgit v1.1