From cc3979f34a886ae4c89d4e3e86a5b0db1669585f Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 5 Nov 2012 11:46:03 +0200 Subject: Move some of the preprocessing from relational to common --- odb/context.cxx | 18 +- odb/context.hxx | 15 +- odb/option-types.cxx | 16 + odb/option-types.hxx | 5 + odb/plugin.cxx | 1 + odb/pragma.cxx | 110 ++-- odb/pragma.hxx | 11 +- odb/processor.cxx | 1365 ++++++++++++++++++++++++++++++++++++++---- odb/relational/processor.cxx | 1067 ++------------------------------- 9 files changed, 1389 insertions(+), 1219 deletions(-) (limited to 'odb') diff --git a/odb/context.cxx b/odb/context.cxx index fbab993..657c283 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -1068,23 +1068,7 @@ type_val_type (semantics::type& t, bool context:: composite_ (semantics::class_& c) { - bool r (true); - - if (c.count ("value")) - { - for (pragma_name_set::const_iterator i (simple_value_pragmas_.begin ()), - e (simple_value_pragmas_.end ()); i != e; ++i) - { - if (c.count (*i)) - { - r = false; - break; - } - } - } - else - r = false; - + bool r (c.count ("value") && !c.count ("simple") && !c.count ("container")); c.set ("composite-value", r); return r; } diff --git a/odb/context.hxx b/odb/context.hxx index 4503e7f..129e5ee 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -380,6 +380,18 @@ public: : 0; } + static semantics::type* + wrapper (semantics::type& t, semantics::names*& hint) + { + if (t.count ("wrapper") && t.get ("wrapper")) + { + hint = t.get ("wrapper-hint"); + return t.get ("wrapper-type"); + } + else + return 0; + } + // Composite value type is a class type that was explicitly marked // as value type and there was no database type mapping provided for // it by the user (specifying the database type makes the value type @@ -428,9 +440,8 @@ public: container (semantics::data_member& m) { // The same type can be used as both a container and a simple value. - // If the member has defines the database type, then it is the latter. // - if (m.count ("type") || m.count ("id-type")) + if (m.count ("simple")) return 0; semantics::type* t (&utype (m)); diff --git a/odb/option-types.cxx b/odb/option-types.cxx index c52935e..6fcd922 100644 --- a/odb/option-types.cxx +++ b/odb/option-types.cxx @@ -60,12 +60,28 @@ static const char* database_[] = "sqlite" }; +static const char* database_name_[] = +{ + "Common Interface", + "SQL Server", + "MySQL", + "Oracle", + "PostgreSQL", + "SQLite" +}; + const char* database:: string () const { return database_[v_]; } +const char* database:: +name () const +{ + return database_name_[v_]; +} + istream& operator>> (istream& is, database& db) { diff --git a/odb/option-types.hxx b/odb/option-types.hxx index 732cd5a..b65589c 100644 --- a/odb/option-types.hxx +++ b/odb/option-types.hxx @@ -56,6 +56,11 @@ struct database const char* string () const; + // Full name (e.g., PostgreSQL). + // + const char* + name () const; + private: value v_; }; diff --git a/odb/plugin.cxx b/odb/plugin.cxx index e7eee3d..5bbe04c 100644 --- a/odb/plugin.cxx +++ b/odb/plugin.cxx @@ -287,6 +287,7 @@ plugin_init (plugin_name_args* plugin_info, plugin_gcc_version*) options_ = ops; pragma_db_ = db; + pragma_multi_ = options_->multi_database (); } if (options_->trace ()) diff --git a/odb/pragma.cxx b/odb/pragma.cxx index ef10a51..8c769ca 100644 --- a/odb/pragma.cxx +++ b/odb/pragma.cxx @@ -27,8 +27,9 @@ virt_declarations virt_declarations_; loc_pragmas loc_pragmas_; decl_pragmas decl_pragmas_; ns_loc_pragmas ns_loc_pragmas_; -pragma_name_set simple_value_pragmas_; + database pragma_db_; +multi_database pragma_multi_; template void @@ -571,6 +572,18 @@ check_spec_decl_type (declaration const& d, return false; } } + else if (p == "simple" || + p == "container") + { + // Apply to both members and types. + // + if (tc != FIELD_DECL && !type) + { + error (l) << "name '" << name << "' in db pragma " << p << " does " + << "not refer to a type or data member" << endl; + return false; + } + } else { error (l) << "unknown db pragma " << p << endl; @@ -2085,6 +2098,62 @@ handle_pragma (cxx_lexer& l, pragma (p, name, val, loc, &check_spec_decl_type, adder), decl, ns); } + // Mark the type or member as simple value or container, depending + // on the pragma. For static multi-database support we only do it + // if the pragma applies to this database since in this case we can + // have different mappings for different databases (e.g., composite + // in one and simple in another). For dynamic multi-database support + // we do this regardless of the database since here the mapping + // should the consistent. + // + // @@ Did we add new simple value or container pragmas and forgot to + // account for them here? + // + if ((qualifier == "value" || qualifier == "member") && + (pragma_multi_ == multi_database::dynamic || db.empty () || + db == pragma_db_.string ())) + { + // We assume a data member is simple only if the database type was + // specified explicitly. + // + if (name == "type" || + name == "id-type" || + (qualifier == "value" && + (name == "null" || + name == "not-null" || + name == "default" || + name == "options"))) + { + add_pragma (pragma (p, "simple", true, loc, &check_spec_decl_type, 0), + decl, + false); + } + else if (name == "table" || + name == "value-type" || + name == "index-type" || + name == "key-type" || + + name == "value-null" || + name == "value-not-null" || + + name == "value-column" || + name == "index-column" || + name == "key-column" || + name == "index-column" || + + name == "value-options" || + name == "index-options" || + name == "key-options" || + name == "index-options" || + + name == "unordered") + { + add_pragma (pragma (p, "container", true, loc, &check_spec_decl_type, 0), + decl, + false); + } + } + // See if there are any more pragmas. // if (tt == CPP_NAME || tt == CPP_KEYWORD) @@ -3276,34 +3345,6 @@ handle_pragma_db (cpp_reader*) extern "C" void register_odb_pragmas (void*, void*) { - // Initialize the list of simple value pragmas. - // - //@@ Did we add new simple value pragmas and forgot to account for - // them here? - // - simple_value_pragmas_.insert ("table"); - simple_value_pragmas_.insert ("type"); - simple_value_pragmas_.insert ("id-type"); - simple_value_pragmas_.insert ("value-type"); - simple_value_pragmas_.insert ("index-type"); - simple_value_pragmas_.insert ("key-type"); - simple_value_pragmas_.insert ("value-column"); - simple_value_pragmas_.insert ("index-column"); - simple_value_pragmas_.insert ("key-column"); - simple_value_pragmas_.insert ("id-column"); - simple_value_pragmas_.insert ("default"); - simple_value_pragmas_.insert ("null"); - simple_value_pragmas_.insert ("not-null"); - simple_value_pragmas_.insert ("value-null"); - simple_value_pragmas_.insert ("value-not-null"); - simple_value_pragmas_.insert ("options"); - simple_value_pragmas_.insert ("value-options"); - simple_value_pragmas_.insert ("index-options"); - simple_value_pragmas_.insert ("key-options"); - simple_value_pragmas_.insert ("id-options"); - simple_value_pragmas_.insert ("unordered"); - - // GCC has a limited number of pragma slots and we have exhausted them. // A workaround is to make 'db' a pragma rather than a namespace. This // way we only have one pragma but the drawback of this approach is the @@ -3387,15 +3428,10 @@ post_process_pragmas () if (name == "value") p = &*j; - else + else if (name == "simple" || name == "container") { - // Make sure it is not one of the simple value pragmas. - // - if (simple_value_pragmas_.find (name) != simple_value_pragmas_.end ()) - { - p = 0; - break; - } + p = 0; + break; } } diff --git a/odb/pragma.hxx b/odb/pragma.hxx index cafaedd..bdded93 100644 --- a/odb/pragma.hxx +++ b/odb/pragma.hxx @@ -252,16 +252,11 @@ extern ns_loc_pragmas ns_loc_pragmas_; typedef std::map decl_pragmas; extern decl_pragmas decl_pragmas_; -// List of pragma names (in context name form) that disqualify a value -// type from being treated as composite (i.e., simple value pragmas). -// -typedef std::set pragma_name_set; -extern pragma_name_set simple_value_pragmas_; - -// Database we are generating code for. Used to ignore database-specific -// pragmas. +// Database we are generating code for as well as multi-database support. +// Used to ignore database-specific pragmas. // extern database pragma_db_; +extern multi_database pragma_multi_; extern "C" void register_odb_pragmas (void*, void*); diff --git a/odb/processor.cxx b/odb/processor.cxx index 616eddc..d5f8c19 100644 --- a/odb/processor.cxx +++ b/odb/processor.cxx @@ -19,6 +19,16 @@ using namespace std; namespace { + // Indirect (dynamic) context values. + // + static semantics::type* + id_tree_type () + { + context& c (context::current ()); + semantics::data_member& id (*context::id_member (*c.top_object)); + return &id.type (); + } + struct data_member: traversal::data_member, context { virtual void @@ -29,6 +39,64 @@ namespace process_access (m, "get"); process_access (m, "set"); + + // We don't need to do any further processing for common if we + // are generating static multi-database code. + // + if (options.database ()[0] == database::common && + options.multi_database () == multi_database::static_) + return; + + semantics::names* hint; + semantics::type& t (utype (m, hint)); + + // Handle wrappers. + // + semantics::type* wt (0), *qwt (0); + semantics::names* whint (0); + if (process_wrapper (t)) + { + qwt = t.get ("wrapper-type"); + whint = t.get ("wrapper-hint"); + wt = &utype (*qwt, whint); + } + + // If the type is const and the member is not id, version, or + // inverse, then mark it as readonly. In case of a wrapper, + // both the wrapper type and the wrapped type must be const. + // To see why, consider these possibilities: + // + // auto_ptr - can modify by setting a new pointer + // const auto_ptr - can modify by changing the pointed-to value + // + if (const_type (m.type ()) && + !(id (m) || version (m) || m.count ("inverse"))) + { + if (qwt == 0 || const_type (*qwt)) + m.set ("readonly", true); + } + + if (composite_wrapper (t)) + return; + + // Process object pointer. The resulting column will be a simple + // or composite value. + // + if (process_object_pointer (m, t)) + return; + + // Before checking if this is a container, check if this member + // or its type were deduced to be a simple value based on the + // pragmas. This is necessary because a container member (e.g., + // vector) can be "overridden" into a simple value (e.g., + // BLOB) with a pragma. + // + if (m.count ("simple") || + t.count ("simple") || + (wt != 0 && wt->count ("simple"))) + return; + + process_container (m, (wt != 0 ? *wt : t)); } // @@ -518,187 +586,1116 @@ namespace } } } - }; - struct class_: traversal::class_, context - { - class_ () - : std_string_ (0), std_string_hint_ (0), access_ (0) + // + // Process wrapper. + // + + bool + process_wrapper (semantics::type& t) { - *this >> member_names_ >> member_; + if (t.count ("wrapper")) + return t.get ("wrapper"); - // Resolve the std::string type node. + // Check this type with wrapper_traits. // - using semantics::scope; + tree inst (instantiate_template (wrapper_traits_, t.tree_node ())); - for (scope::names_iterator_pair ip (unit.find ("std")); - ip.first != ip.second; ++ip.first) + if (inst == 0) { - if (scope* ns = dynamic_cast (&ip.first->named ())) - { - scope::names_iterator_pair jp (ns->find ("string")); + t.set ("wrapper", false); + return false; + } - if (jp.first != jp.second) - { - std_string_ = dynamic_cast ( - &jp.first->named ()); - std_string_hint_ = &*jp.first; + // @@ This points to the primary template, not the specialization. + // + tree decl (TYPE_NAME (inst)); + + string f (DECL_SOURCE_FILE (decl)); + size_t l (DECL_SOURCE_LINE (decl)); + size_t c (DECL_SOURCE_COLUMN (decl)); + + // Get the wrapped type. + // + try + { + tree decl ( + lookup_qualified_name ( + inst, get_identifier ("wrapped_type"), true, false)); + + if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) + throw operation_failed (); + + // The wrapped_type alias is a typedef in an instantiation + // that we just instantiated dynamically. As a result there + // is no semantic graph edges corresponding to this typedef + // since we haven't parsed it yet. So to get the tree node + // that can actually be resolved to the graph node, we use + // the source type of this typedef. + // + tree type (DECL_ORIGINAL_TYPE (decl)); + + semantics::type& wt ( + dynamic_cast (*unit.find (type))); + + // Find the hint. + // + semantics::names* wh (0); + + for (tree ot (DECL_ORIGINAL_TYPE (decl)); + ot != 0; + ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0) + { + if ((wh = unit.find_hint (ot))) break; - } + + decl = TYPE_NAME (ot); } - } - assert (std_string_ != 0); // No std::string? + t.set ("wrapper-type", &wt); + t.set ("wrapper-hint", wh); + } + catch (operation_failed const&) + { + os << f << ":" << l << ":" << c << ": error: " + << "wrapper_traits specialization does not define the " + << "wrapped_type type" << endl; + throw; + } - // Resolve odb::access, if any. + // Get the null_handler flag. // - tree odb = lookup_qualified_name ( - global_namespace, get_identifier ("odb"), false, false); + bool null_handler (false); - if (odb != error_mark_node) + try { - access_ = lookup_qualified_name ( - odb, get_identifier ("access"), true, false); + tree nh ( + lookup_qualified_name ( + inst, get_identifier ("null_handler"), false, false)); - access_ = (access_ != error_mark_node ? TREE_TYPE (access_) : 0); - } - } + if (nh == error_mark_node || TREE_CODE (nh) != VAR_DECL) + throw operation_failed (); - virtual void - traverse (type& c) - { - class_kind_type k (class_kind (c)); + // Instantiate this decalaration so that we can get its value. + // + if (DECL_TEMPLATE_INSTANTIATION (nh) && + !DECL_TEMPLATE_INSTANTIATED (nh) && + !DECL_EXPLICIT_INSTANTIATION (nh)) + instantiate_decl (nh, false, false); - if (k == class_other) - return; + tree init (DECL_INITIAL (nh)); - // Check if odb::access is a friend of this class. + if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) + throw operation_failed (); + + unsigned long long e; + + { + HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); + HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); + + unsigned long long l (hwl); + unsigned long long h (hwh); + unsigned short width (HOST_BITS_PER_WIDE_INT); + + e = (h << width) + l; + } + + null_handler = static_cast (e); + t.set ("wrapper-null-handler", null_handler); + } + catch (operation_failed const&) + { + os << f << ":" << l << ":" << c << ": error: " + << "wrapper_traits specialization does not define the " + << "null_handler constant" << endl; + throw; + } + + // Get the null_default flag. // - c.set ("friend", access_ != 0 && is_friend (c.tree_node (), access_)); + if (null_handler) + { + try + { + tree nh ( + lookup_qualified_name ( + inst, get_identifier ("null_default"), false, false)); - // Assign pointer. + if (nh == error_mark_node || TREE_CODE (nh) != VAR_DECL) + throw operation_failed (); + + // Instantiate this decalaration so that we can get its value. + // + if (DECL_TEMPLATE_INSTANTIATION (nh) && + !DECL_TEMPLATE_INSTANTIATED (nh) && + !DECL_EXPLICIT_INSTANTIATION (nh)) + instantiate_decl (nh, false, false); + + tree init (DECL_INITIAL (nh)); + + if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) + throw operation_failed (); + + unsigned long long e; + + { + HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); + HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); + + unsigned long long l (hwl); + unsigned long long h (hwh); + unsigned short width (HOST_BITS_PER_WIDE_INT); + + e = (h << width) + l; + } + + t.set ("wrapper-null-default", static_cast (e)); + } + catch (operation_failed const&) + { + os << f << ":" << l << ":" << c << ": error: " + << "wrapper_traits specialization does not define the " + << "null_default constant" << endl; + throw; + } + } + + // Check if the wrapper is a TR1 template instantiation. // - if (k == class_object || k == class_view) - assign_pointer (c); + if (tree ti = TYPE_TEMPLATE_INFO (t.tree_node ())) + { + tree decl (TI_TEMPLATE (ti)); // DECL_TEMPLATE - if (k == class_object) - traverse_object (c); + // Get to the most general template declaration. + // + while (DECL_TEMPLATE_INFO (decl)) + decl = DECL_TI_TEMPLATE (decl); - names (c); + bool& tr1 (features.tr1_pointer); + bool& boost (features.boost_pointer); + + 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; + } + + t.set ("wrapper", true); + return true; } // - // Object. + // Process object pointer. // - virtual void - traverse_object (type& c) + semantics::class_* + process_object_pointer (semantics::data_member& m, + semantics::type& t, + string const& kp = string ()) { - semantics::class_* poly_root (polymorphic (c)); - - // Determine whether it is a session object. + // The overall idea is as follows: try to instantiate the pointer + // traits class template. If we are successeful, then get the + // element type and see if it is an object. // - if (!c.count ("session")) + using semantics::class_; + using semantics::data_member; + + class_* c (0); + + if (t.count ("element-type")) + c = t.get ("element-type"); + else { - // If this is a derived class in a polymorphic hierarchy, - // then it should have the same session value as the root. + tree inst (instantiate_template (pointer_traits_, t.tree_node ())); + + if (inst == 0) + return 0; + + // @@ This points to the primary template, not the specialization. // - if (poly_root != 0 && poly_root != &c) - c.set ("session", session (*poly_root)); - else + tree decl (TYPE_NAME (inst)); + + string fl (DECL_SOURCE_FILE (decl)); + size_t ln (DECL_SOURCE_LINE (decl)); + size_t cl (DECL_SOURCE_COLUMN (decl)); + + // Get the element type. + // + tree tn (0); + try { - // See if any of the namespaces containing this class specify - // the session value. + tree decl ( + lookup_qualified_name ( + inst, get_identifier ("element_type"), true, false)); + + if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) + throw operation_failed (); + + tn = TYPE_MAIN_VARIANT (TREE_TYPE (decl)); + + // Check if the pointer is a TR1 template instantiation. // - bool found (false); - for (semantics::scope* s (&c.scope ());; s = &s->scope_ ()) + if (tree ti = TYPE_TEMPLATE_INFO (t.tree_node ())) { - using semantics::namespace_; + decl = TI_TEMPLATE (ti); // DECL_TEMPLATE - namespace_* ns (dynamic_cast (s)); + // Get to the most general template declaration. + // + while (DECL_TEMPLATE_INFO (decl)) + decl = DECL_TI_TEMPLATE (decl); - if (ns == 0) - continue; // Some other scope. + bool& tr1 (features.tr1_pointer); + bool& boost (features.boost_pointer); - if (ns->extension ()) - ns = &ns->original (); + string n (decl_as_string (decl, TFF_PLAIN_IDENTIFIER)); - if (ns->count ("session")) - { - c.set ("session", ns->get ("session")); - found = true; - break; - } + // 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; - if (ns->global_scope ()) - break; + boost = boost + || n.compare (0, 17, "boost::shared_ptr") == 0 + || n.compare (0, 19, "::boost::shared_ptr") == 0; } - - // If still not found, then use the default value. - // - if (!found) - c.set ("session", options.generate_session ()); } - } + catch (operation_failed const&) + { + os << fl << ":" << ln << ":" << cl << ": error: pointer_traits " + << "specialization does not define the 'element_type' type" + << endl; + throw; + } - if (session (c)) - features.session_object = true; + c = dynamic_cast (unit.find (tn)); - if (poly_root != 0) - { - using namespace semantics; + if (c == 0 || !object (*c)) + return 0; - semantics::data_member& idm (*id_member (*poly_root)); + t.set ("element-type", c); - if (poly_root != &c) + // Determine the pointer kind. + // + try { - // 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 ()); + tree kind ( + lookup_qualified_name ( + inst, get_identifier ("kind"), false, false)); - semantics::data_member& m ( - unit.new_node (f, l, col, tree (0))); - m.set ("virtual", true); + if (kind == error_mark_node || TREE_CODE (kind) != VAR_DECL) + throw operation_failed (); - // Make it the first member in the class. + // Instantiate this decalaration so that we can get its value. // - node_position np (c, c.names_end ()); - unit.new_edge ( - np, m, idm.name (), access::public_); + if (DECL_TEMPLATE_INSTANTIATION (kind) && + !DECL_TEMPLATE_INSTANTIATED (kind) && + !DECL_EXPLICIT_INSTANTIATION (kind)) + instantiate_decl (kind, false, false); + + tree init (DECL_INITIAL (kind)); + + if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) + throw operation_failed (); + + unsigned long long e; - // 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 (f, l, col, ptr)); - unit.insert (ptr, p); - unit.new_edge (p, *poly_root); - assert (poly_root->pointed_p ()); - } + HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); + HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); - unit.new_edge (m, poly_root->pointed ().pointer ()); + unsigned long long l (hwl); + unsigned long long h (hwh); + unsigned short width (HOST_BITS_PER_WIDE_INT); - // Mark it as a special kind of id. - // - m.set ("id", true); - m.set ("polymorphic-ref", true); + e = (h << width) + l; + } + + pointer_kind_type pk = static_cast (e); + t.set ("pointer-kind", pk); } - else + catch (operation_failed const&) { - // 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 + os << fl << ":" << ln << ":" << cl << ": error: pointer_traits " + << "specialization does not define the 'kind' constant" << endl; + throw; + } + + // Get the lazy flag. + // + try + { + tree lazy ( + lookup_qualified_name ( + inst, get_identifier ("lazy"), false, false)); + + if (lazy == error_mark_node || TREE_CODE (lazy) != VAR_DECL) + throw operation_failed (); + + // Instantiate this decalaration so that we can get its value. + // + if (DECL_TEMPLATE_INSTANTIATION (lazy) && + !DECL_TEMPLATE_INSTANTIATED (lazy) && + !DECL_EXPLICIT_INSTANTIATION (lazy)) + instantiate_decl (lazy, false, false); + + tree init (DECL_INITIAL (lazy)); + + if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) + throw operation_failed (); + + unsigned long long e; + + { + HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); + HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); + + unsigned long long l (hwl); + unsigned long long h (hwh); + unsigned short width (HOST_BITS_PER_WIDE_INT); + + e = (h << width) + l; + } + + t.set ("pointer-lazy", static_cast (e)); + } + catch (operation_failed const&) + { + os << fl << ":" << ln << ":" << cl << ": error: pointer_traits " + << "specialization does not define the 'kind' constant" << endl; + throw; + } + } + + // Make sure the pointed-to class is complete. + // + if (!c->complete ()) + { + os << m.file () << ":" << m.line () << ":" << m.column () << ": " + << "error: pointed-to class '" << class_fq_name (*c) << "' " + << "is incomplete" << endl; + + os << c->file () << ":" << c->line () << ":" << c->column () << ": " + << "info: class '" << class_name (*c) << "' is declared here" + << endl; + + os << c->file () << ":" << c->line () << ":" << c->column () << ": " + << "info: consider including its definition with the " + << "--odb-epilogue option" << endl; + + throw operation_failed (); + } + + // Make sure the pointed-to class is not reuse-abstract. + // + if (abstract (*c) && !polymorphic (*c)) + { + os << m.file () << ":" << m.line () << ":" << m.column () << ": " + << "error: pointed-to class '" << class_fq_name (*c) << "' " + << "is abstract" << endl; + + os << c->file () << ":" << c->line () << ":" << c->column () << ": " + << "info: class '" << class_name (*c) << "' is defined here" + << endl; + + throw operation_failed (); + } + + // Make sure the pointed-to class has object id. + // + if (id_member (*c) == 0) + { + os << m.file () << ":" << m.line () << ":" << m.column () << ": " + << "error: pointed-to class '" << class_fq_name (*c) << "' " + << "has no object id" << endl; + + os << c->file () << ":" << c->line () << ":" << c->column () << ": " + << "info: class '" << class_name (*c) << "' is defined here" + << endl; + + throw operation_failed (); + } + + // See if this is the inverse side of a bidirectional relationship. + // If so, then resolve the member and cache it in the context. + // + if (m.count ("inverse")) + { + string name (m.get ("inverse")); + location_t loc (m.get ("inverse-location")); + + try + { + data_member& im ( + c->lookup (name, class_::include_hidden)); + + // @@ Would be good to check that the other end is actually + // an object pointer, is not marked as transient or inverse, + // and points to the correct object. But the other class may + // not have been processed yet. + // + m.remove ("inverse"); + m.set (kp + (kp.empty () ? "": "-") + "inverse", &im); + } + catch (semantics::unresolved const& e) + { + if (e.type_mismatch) + error (loc) << "name '" << name << "' in '#pragma db " << + "inverse' does not refer to a data member" << endl; + else + error (loc) << "unable to resolve data member '" << name << + "' specified with '#pragma db inverse'" << endl; + + throw operation_failed (); + } + catch (semantics::ambiguous const& e) + { + error (loc) << "data member name '" << name << "' specified " << + "with '#pragma db inverse' is ambiguous" << endl; + + info (e.first.named ().location ()) << "could resolve to this " << + "data member" << endl; + + info (e.second.named ().location ()) << "or could resolve to " << + "this data member" << endl; + + throw operation_failed (); + } + } + + return c; + } + + // + // Process container. + // + + void + process_container_value (semantics::type& t, + semantics::data_member& m, + string const& prefix, + bool obj_ptr) + { + process_wrapper (t); + + if (composite_wrapper (t)) + return; + + if (obj_ptr) + process_object_pointer (m, t, prefix); + } + + bool + process_container (semantics::data_member& m, semantics::type& t) + { + // The overall idea is as follows: try to instantiate the container + // traits class template. If we are successeful, then this is a + // container type and we can extract the various information from + // the instantiation. Otherwise, this is not a container. + // + + container_kind_type ck; + semantics::type* vt (0); + semantics::type* it (0); + semantics::type* kt (0); + + semantics::names* vh (0); + semantics::names* ih (0); + semantics::names* kh (0); + + if (t.count ("container-kind")) + { + ck = t.get ("container-kind"); + vt = t.get ("value-tree-type"); + vh = t.get ("value-tree-hint"); + + if (ck == ck_ordered) + { + it = t.get ("index-tree-type"); + ih = t.get ("index-tree-hint"); + } + + if (ck == ck_map || ck == ck_multimap) + { + kt = t.get ("key-tree-type"); + kh = t.get ("key-tree-hint"); + } + } + else + { + tree inst (instantiate_template (container_traits_, t.tree_node ())); + + if (inst == 0) + return false; + + // @@ This points to the primary template, not the specialization. + // + tree decl (TYPE_NAME (inst)); + + string f (DECL_SOURCE_FILE (decl)); + size_t l (DECL_SOURCE_LINE (decl)); + size_t c (DECL_SOURCE_COLUMN (decl)); + + // Determine the container kind. + // + try + { + tree kind ( + lookup_qualified_name ( + inst, get_identifier ("kind"), false, false)); + + if (kind == error_mark_node || TREE_CODE (kind) != VAR_DECL) + throw operation_failed (); + + + // Instantiate this decalaration so that we can get its value. + // + if (DECL_TEMPLATE_INSTANTIATION (kind) && + !DECL_TEMPLATE_INSTANTIATED (kind) && + !DECL_EXPLICIT_INSTANTIATION (kind)) + instantiate_decl (kind, false, false); + + tree init (DECL_INITIAL (kind)); + + if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) + throw operation_failed (); + + unsigned long long e; + + { + HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); + HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); + + unsigned long long l (hwl); + unsigned long long h (hwh); + unsigned short width (HOST_BITS_PER_WIDE_INT); + + e = (h << width) + l; + } + + ck = static_cast (e); + } + catch (operation_failed const&) + { + os << f << ":" << l << ":" << c << ": error: " + << "container_traits specialization does not define the " + << "container kind constant" << endl; + + throw; + } + + t.set ("container-kind", ck); + + // Mark id column as not null. + // + t.set ("id-not-null", true); + + // Get the value type. + // + try + { + tree decl ( + lookup_qualified_name ( + inst, get_identifier ("value_type"), true, false)); + + if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) + throw operation_failed (); + + tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); + vt = &dynamic_cast (*unit.find (type)); + + // Find the hint. + // + for (tree ot (DECL_ORIGINAL_TYPE (decl)); + ot != 0; + ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0) + { + if ((vh = unit.find_hint (ot))) + break; + + decl = TYPE_NAME (ot); + } + } + catch (operation_failed const&) + { + os << f << ":" << l << ":" << c << ": error: " + << "container_traits specialization does not define the " + << "value_type type" << endl; + + throw; + } + + t.set ("value-tree-type", vt); + t.set ("value-tree-hint", vh); + + // If we have a set container, automatically mark the value + // column as not null. If we already have an explicit null for + // this column, issue an error. + // + if (ck == ck_set) + { + if (t.count ("value-null")) + { + os << t.file () << ":" << t.line () << ":" << t.column () << ":" + << " error: set container cannot contain null values" << endl; + + throw operation_failed (); + } + else + t.set ("value-not-null", true); + } + + // Issue a warning if we are relaxing null-ness in the + // container type. + // + if (t.count ("value-null") && vt->count ("not-null")) + { + os << t.file () << ":" << t.line () << ":" << t.column () << ":" + << " warning: container value declared null while its type " + << "is declared not null" << endl; + } + + // Get the index type for ordered containers. + // + if (ck == ck_ordered) + { + try + { + tree decl ( + lookup_qualified_name ( + inst, get_identifier ("index_type"), true, false)); + + if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) + throw operation_failed (); + + tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); + it = &dynamic_cast (*unit.find (type)); + + // Find the hint. + // + for (tree ot (DECL_ORIGINAL_TYPE (decl)); + ot != 0; + ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0) + { + if ((ih = unit.find_hint (ot))) + break; + + decl = TYPE_NAME (ot); + } + } + catch (operation_failed const&) + { + os << f << ":" << l << ":" << c << ": error: " + << "container_traits specialization does not define the " + << "index_type type" << endl; + + throw; + } + + t.set ("index-tree-type", it); + t.set ("index-tree-hint", ih); + t.set ("index-not-null", true); + } + + // Get the key type for maps. + // + if (ck == ck_map || ck == ck_multimap) + { + try + { + tree decl ( + lookup_qualified_name ( + inst, get_identifier ("key_type"), true, false)); + + if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) + throw operation_failed (); + + tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); + kt = &dynamic_cast (*unit.find (type)); + + // Find the hint. + // + for (tree ot (DECL_ORIGINAL_TYPE (decl)); + ot != 0; + ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0) + { + if ((kh = unit.find_hint (ot))) + break; + + decl = TYPE_NAME (ot); + } + } + catch (operation_failed const&) + { + os << f << ":" << l << ":" << c << ": error: " + << "container_traits specialization does not define the " + << "key_type type" << endl; + + throw; + } + + t.set ("key-tree-type", kt); + t.set ("key-tree-hint", kh); + t.set ("key-not-null", true); + } + } + + // Process member data. + // + m.set ("id-tree-type", &id_tree_type); + + process_container_value (*vt, m, "value", true); + + if (it != 0) + process_container_value (*it, m, "index", false); + + if (kt != 0) + process_container_value (*kt, m, "key", false); + + // If this is an inverse side of a bidirectional object relationship + // and it is an ordered container, mark it as unordred since there is + // no concept of order in this construct. + // + if (ck == ck_ordered && m.count ("value-inverse")) + m.set ("unordered", true); + + // Issue an error if we have a null column in a set container. + // This can only happen if the value is declared as null in + // the member. + // + if (ck == ck_set && m.count ("value-null")) + { + os << m.file () << ":" << m.line () << ":" << m.column () << ":" + << " error: set container cannot contain null values" << endl; + + throw operation_failed (); + } + + // Issue a warning if we are relaxing null-ness in the member. + // + if (m.count ("value-null") && + (t.count ("value-not-null") || vt->count ("not-null"))) + { + os << m.file () << ":" << m.line () << ":" << m.column () << ":" + << " warning: container value declared null while the container " + << "type or value type declares it as not null" << endl; + } + + return true; + } + + // + // Implementation details (c-tor, helpers). + // + + data_member () + { + // Find the odb namespace. + // + tree odb = lookup_qualified_name ( + global_namespace, get_identifier ("odb"), false, false); + + if (odb == error_mark_node) + { + os << unit.file () << ": error: unable to resolve odb namespace" + << endl; + + throw operation_failed (); + } + + // Find wrapper traits. + // + wrapper_traits_ = lookup_qualified_name ( + odb, get_identifier ("wrapper_traits"), true, false); + + if (wrapper_traits_ == error_mark_node || + !DECL_CLASS_TEMPLATE_P (wrapper_traits_)) + { + os << unit.file () << ": error: unable to resolve wrapper_traits " + << "in the odb namespace" << endl; + + throw operation_failed (); + } + + // Find pointer traits. + // + pointer_traits_ = lookup_qualified_name ( + odb, get_identifier ("pointer_traits"), true, false); + + if (pointer_traits_ == error_mark_node || + !DECL_CLASS_TEMPLATE_P (pointer_traits_)) + { + os << unit.file () << ": error: unable to resolve pointer_traits " + << "in the odb namespace" << endl; + + throw operation_failed (); + } + + // Find the access class. + // + tree access = lookup_qualified_name ( + odb, get_identifier ("access"), true, false); + + if (access == error_mark_node) + { + os << unit.file () << ": error: unable to resolve access class" + << "in the odb namespace" << endl; + + throw operation_failed (); + } + + access = TREE_TYPE (access); + + // Find container_traits. + // + container_traits_ = lookup_qualified_name ( + access, get_identifier ("container_traits"), true, false); + + if (container_traits_ == error_mark_node || + !DECL_CLASS_TEMPLATE_P (container_traits_)) + { + os << unit.file () << ": error: unable to resolve container_traits " + << "in the odb namespace" << endl; + + throw operation_failed (); + } + } + + static tree + instantiate_template (tree t, tree arg) + { + tree args (make_tree_vec (1)); + TREE_VEC_ELT (args, 0) = arg; + + // This step should succeed regardles of whether there is a + // specialization for this type. + // + tree inst ( + lookup_template_class (t, args, 0, 0, 0, tf_warning_or_error)); + + if (inst == error_mark_node) + { + // Diagnostics has already been issued by lookup_template_class. + // + throw operation_failed (); + } + + inst = TYPE_MAIN_VARIANT (inst); + + // The instantiation may already be complete if it matches a + // (complete) specialization or was used before. + // + if (!COMPLETE_TYPE_P (inst)) + inst = instantiate_class_template (inst); + + // If we cannot instantiate this type, assume there is no suitable + // specialization for it. + // + if (inst == error_mark_node || !COMPLETE_TYPE_P (inst)) + return 0; + + return inst; + } + + private: + tree wrapper_traits_; + tree pointer_traits_; + tree container_traits_; + }; + + 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 (&ip.first->named ())) + { + scope::names_iterator_pair jp (ns->find ("string")); + + if (jp.first != jp.second) + { + std_string_ = dynamic_cast ( + &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); + else if (k == class_view) + traverse_view (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 (s)); + + if (ns == 0) + continue; // Some other scope. + + if (ns->extension ()) + ns = &ns->original (); + + if (ns->count ("session")) + { + c.set ("session", ns->get ("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 (f, l, col, tree (0))); + m.set ("virtual", true); + + // Make it the first member in the class. + // + node_position np (c, c.names_end ()); + unit.new_edge ( + 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 (f, l, col, ptr)); + unit.insert (ptr, p); + unit.new_edge (p, *poly_root); + assert (poly_root->pointed_p ()); + } + + unit.new_edge (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 ("polymorphic-location")); @@ -729,6 +1726,124 @@ namespace } } + // + // View. + // + + virtual void + traverse_view (type& c) + { + // Resolve referenced objects from tree nodes to semantic graph + // nodes. Also populate maps and compute counts. + // + 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 (c.count ("objects")) + { + using semantics::class_; + + view_objects& objs (c.get ("objects")); + + for (view_objects::iterator i (objs.begin ()); i != objs.end (); ++i) + { + if (i->kind != view_object::object) + { + tbl_count++; + continue; + } + else + obj_count++; + + tree n (TYPE_MAIN_VARIANT (i->obj_node)); + + if (TREE_CODE (n) != RECORD_TYPE) + { + error (i->loc) << "name '" << i->obj_name << "' in db pragma " << + "object does not name a class" << endl; + + throw operation_failed (); + } + + class_& o (dynamic_cast (*unit.find (n))); + + if (!object (o)) + { + error (i->loc) << "name '" << i->obj_name << "' in db pragma " << + "object does not name a persistent class" << endl; + + info (o.location ()) << "class '" << i->obj_name << "' is " << + "defined here" << endl; + + throw operation_failed (); + } + + i->obj = &o; + + if (i->alias.empty ()) + { + if (!omap.insert (view_object_map::value_type (&o, &*i)).second) + { + error (i->loc) << "persistent class '" << i->obj_name << + "' is used in the view more than once" << endl; + + error (omap[&o]->loc) << "previously used here" << endl; + + info (i->loc) << "use the alias clause to assign it a " << + "different name" << endl; + + throw operation_failed (); + } + + // Also add the bases of a polymorphic object. + // + class_* poly_root (polymorphic (o)); + + if (poly_root != 0 && poly_root != &o) + { + for (class_* b (&polymorphic_base (o));; + b = &polymorphic_base (*b)) + { + if (!omap.insert (view_object_map::value_type (b, &*i)).second) + { + error (i->loc) << "base class '" << class_name (*b) << + "' is used in the view more than once" << endl; + + error (omap[b]->loc) << "previously used here" << endl; + + info (i->loc) << "use the alias clause to assign it a " << + "different name" << endl; + + throw operation_failed (); + } + + if (b == poly_root) + break; + } + } + } + else + { + if (!amap.insert ( + view_alias_map::value_type (i->alias, &*i)).second) + { + error (i->loc) << "alias '" << i->alias << "' is used in " << + "the view more than once" << endl; + + throw operation_failed (); + } + } + } + } + } + + // + // Assign object/view pointer. + // + void assign_pointer (type& c) { diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx index 4213602..88e86fc 100644 --- a/odb/relational/processor.cxx +++ b/odb/relational/processor.cxx @@ -23,14 +23,6 @@ namespace relational { // Indirect (dynamic) context values. // - static semantics::type* - id_tree_type () - { - context& c (context::current ()); - semantics::data_member& id (*context::id_member (*c.top_object)); - return &id.type (); - } - static string id_column_type () { @@ -41,79 +33,6 @@ namespace relational struct data_member: traversal::data_member, context { - data_member () - { - // Find the odb namespace. - // - tree odb = lookup_qualified_name ( - global_namespace, get_identifier ("odb"), false, false); - - if (odb == error_mark_node) - { - os << unit.file () << ": error: unable to resolve odb namespace" - << endl; - - throw operation_failed (); - } - - // Find wrapper traits. - // - wrapper_traits_ = lookup_qualified_name ( - odb, get_identifier ("wrapper_traits"), true, false); - - if (wrapper_traits_ == error_mark_node || - !DECL_CLASS_TEMPLATE_P (wrapper_traits_)) - { - os << unit.file () << ": error: unable to resolve wrapper_traits " - << "in the odb namespace" << endl; - - throw operation_failed (); - } - - // Find pointer traits. - // - pointer_traits_ = lookup_qualified_name ( - odb, get_identifier ("pointer_traits"), true, false); - - if (pointer_traits_ == error_mark_node || - !DECL_CLASS_TEMPLATE_P (pointer_traits_)) - { - os << unit.file () << ": error: unable to resolve pointer_traits " - << "in the odb namespace" << endl; - - throw operation_failed (); - } - - // Find the access class. - // - tree access = lookup_qualified_name ( - odb, get_identifier ("access"), true, false); - - if (access == error_mark_node) - { - os << unit.file () << ": error: unable to resolve access class" - << "in the odb namespace" << endl; - - throw operation_failed (); - } - - access = TREE_TYPE (access); - - // Find container_traits. - // - container_traits_ = lookup_qualified_name ( - access, get_identifier ("container_traits"), true, false); - - if (container_traits_ == error_mark_node || - !DECL_CLASS_TEMPLATE_P (container_traits_)) - { - os << unit.file () << ": error: unable to resolve container_traits " - << "in the odb namespace" << endl; - - throw operation_failed (); - } - } - virtual void traverse (semantics::data_member& m) { @@ -123,31 +42,10 @@ namespace relational semantics::names* hint; semantics::type& t (utype (m, hint)); - // Handle wrappers. - // - semantics::type* wt (0), *qwt (0); + semantics::type* wt; semantics::names* whint (0); - if (process_wrapper (t)) - { - qwt = t.get ("wrapper-type"); - whint = t.get ("wrapper-hint"); - wt = &utype (*qwt, whint); - } - - // If the type is const and the member is not id, version, or - // inverse, then mark it as readonly. In case of a wrapper, - // both the wrapper type and the wrapped type must be const. - // To see why, consider these possibilities: - // - // auto_ptr - can modify by setting a new pointer - // const auto_ptr - can modify by changing the pointed-to value - // - if (const_type (m.type ()) && - !(id (m) || version (m) || m.count ("inverse"))) - { - if (qwt == 0 || const_type (*qwt)) - m.set ("readonly", true); - } + if ((wt = wrapper (t, whint))) + wt = &utype (*wt, whint); // Determine the member kind. // @@ -175,7 +73,7 @@ namespace relational id_type = type; } - if (semantics::class_* c = process_object_pointer (m, t)) + if (semantics::class_* c = object_pointer (t)) { // This is an object pointer. The column type is the pointed-to // object id type. @@ -185,20 +83,17 @@ namespace relational semantics::names* idhint; semantics::type& idt (utype (id, idhint)); - semantics::type* wt (0); - semantics::names* whint (0); - if (process_wrapper (idt)) - { - whint = idt.get ("wrapper-hint"); - wt = &utype (*idt.get ("wrapper-type"), whint); - } - // The id type can be a composite value type. // if (composite_wrapper (idt)) kind = composite; else { + semantics::type* wt; + semantics::names* whint (0); + if ((wt = wrapper (idt, whint))) + wt = &utype (*wt, whint); + if (type.empty () && id.count ("id-type")) type = id.get ("id-type"); @@ -284,10 +179,11 @@ namespace relational // If not a simple value, see if this is a container. // - if (kind == unknown && - (process_container (m, t) || - (wt != 0 && process_container (m, *wt)))) + if (kind == unknown && context::container (m)) + { + process_container (m, (wt != 0 ? *wt : t)); kind = container; + } // If it is none of the above then we have an error. // @@ -296,7 +192,7 @@ namespace relational os << m.file () << ":" << m.line () << ":" << m.column () << ":" << " error: unable to map C++ type '" << t.fq_name (hint) << "' used in data member '" << m.name () << "' to a " - << "database type" << endl; + << db.name () << " database type" << endl; os << m.file () << ":" << m.line () << ":" << m.column () << ":" << " info: use '#pragma db type' to specify the database type" @@ -360,17 +256,12 @@ namespace relational string const& prefix, bool obj_ptr) { - semantics::type* wt (0); - semantics::names* wh (0); - if (process_wrapper (t)) - { - wt = t.get ("wrapper-type"); - wh = t.get ("wrapper-hint"); - } - if (composite_wrapper (t)) return; + semantics::names* wh (0); + semantics::type* wt (wrapper (t, wh)); + string type; semantics::type& ct (utype (m)); @@ -386,7 +277,7 @@ namespace relational type = ct.get (prefix + "-type"); semantics::class_* c; - if (obj_ptr && (c = process_object_pointer (m, t, prefix))) + if (obj_ptr && (c = object_pointer (t))) { // This is an object pointer. The column type is the pointed-to // object id type. @@ -396,19 +287,16 @@ namespace relational semantics::names* idhint; semantics::type& idt (utype (id, idhint)); - semantics::type* wt (0); - semantics::names* whint (0); - if (process_wrapper (idt)) - { - whint = idt.get ("wrapper-hint"); - wt = &utype (*idt.get ("wrapper-type"), whint); - } - // Nothing to do if this is a composite value type. // if (composite_wrapper (idt)) return; + semantics::type* wt (0); + semantics::names* whint (0); + if ((wt = wrapper (idt, whint))) + wt = &utype (*wt, whint); + if (type.empty () && id.count ("id-type")) type = id.get ("id-type"); @@ -468,7 +356,8 @@ namespace relational os << m.file () << ":" << m.line () << ":" << m.column () << ":" << " error: unable to map C++ type '" << fq_type << "' used in " - << "data member '" << m.name () << "' to a database type" << endl; + << "data member '" << m.name () << "' to a " << db.name () + << " database type" << endl; os << m.file () << ":" << m.line () << ":" << m.column () << ":" << " info: use '#pragma db " << prefix << "_type' to specify the " @@ -477,264 +366,32 @@ namespace relational throw operation_failed (); } - bool + void process_container (semantics::data_member& m, semantics::type& t) { - // The overall idea is as follows: try to instantiate the container - // traits class template. If we are successeful, then this is a - // container type and we can extract the various information from - // the instantiation. Otherwise, this is not a container. - // - - container_kind_type ck; - semantics::type* vt (0); + container_kind_type ck (t.get ("container-kind")); + semantics::type* vt (t.get ("value-tree-type")); semantics::type* it (0); semantics::type* kt (0); - semantics::names* vh (0); + semantics::names* vh (t.get ("value-tree-hint")); semantics::names* ih (0); semantics::names* kh (0); - if (t.count ("container-kind")) + if (ck == ck_ordered) { - ck = t.get ("container-kind"); - vt = t.get ("value-tree-type"); - vh = t.get ("value-tree-hint"); - - if (ck == ck_ordered) - { - it = t.get ("index-tree-type"); - ih = t.get ("index-tree-hint"); - } - - if (ck == ck_map || ck == ck_multimap) - { - kt = t.get ("key-tree-type"); - kh = t.get ("key-tree-hint"); - } + it = t.get ("index-tree-type"); + ih = t.get ("index-tree-hint"); } - else - { - tree inst (instantiate_template (container_traits_, t.tree_node ())); - - if (inst == 0) - return false; - - // @@ This points to the primary template, not the specialization. - // - tree decl (TYPE_NAME (inst)); - - string f (DECL_SOURCE_FILE (decl)); - size_t l (DECL_SOURCE_LINE (decl)); - size_t c (DECL_SOURCE_COLUMN (decl)); - - // Determine the container kind. - // - try - { - tree kind ( - lookup_qualified_name ( - inst, get_identifier ("kind"), false, false)); - - if (kind == error_mark_node || TREE_CODE (kind) != VAR_DECL) - throw operation_failed (); - - - // Instantiate this decalaration so that we can get its value. - // - if (DECL_TEMPLATE_INSTANTIATION (kind) && - !DECL_TEMPLATE_INSTANTIATED (kind) && - !DECL_EXPLICIT_INSTANTIATION (kind)) - instantiate_decl (kind, false, false); - - tree init (DECL_INITIAL (kind)); - - if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) - throw operation_failed (); - - unsigned long long e; - - { - HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); - HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); - - unsigned long long l (hwl); - unsigned long long h (hwh); - unsigned short width (HOST_BITS_PER_WIDE_INT); - - e = (h << width) + l; - } - - ck = static_cast (e); - } - catch (operation_failed const&) - { - os << f << ":" << l << ":" << c << ": error: " - << "container_traits specialization does not define the " - << "container kind constant" << endl; - - throw; - } - - t.set ("container-kind", ck); - - // Mark id column as not null. - // - t.set ("id-not-null", true); - - // Get the value type. - // - try - { - tree decl ( - lookup_qualified_name ( - inst, get_identifier ("value_type"), true, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) - throw operation_failed (); - tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); - vt = &dynamic_cast (*unit.find (type)); - - // Find the hint. - // - for (tree ot (DECL_ORIGINAL_TYPE (decl)); - ot != 0; - ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0) - { - if ((vh = unit.find_hint (ot))) - break; - - decl = TYPE_NAME (ot); - } - } - catch (operation_failed const&) - { - os << f << ":" << l << ":" << c << ": error: " - << "container_traits specialization does not define the " - << "value_type type" << endl; - - throw; - } - - t.set ("value-tree-type", vt); - t.set ("value-tree-hint", vh); - - // If we have a set container, automatically mark the value - // column as not null. If we already have an explicit null for - // this column, issue an error. - // - if (ck == ck_set) - { - if (t.count ("value-null")) - { - os << t.file () << ":" << t.line () << ":" << t.column () << ":" - << " error: set container cannot contain null values" << endl; - - throw operation_failed (); - } - else - t.set ("value-not-null", true); - } - - // Issue a warning if we are relaxing null-ness in the - // container type. - // - if (t.count ("value-null") && vt->count ("not-null")) - { - os << t.file () << ":" << t.line () << ":" << t.column () << ":" - << " warning: container value declared null while its type " - << "is declared not null" << endl; - } - - // Get the index type for ordered containers. - // - if (ck == ck_ordered) - { - try - { - tree decl ( - lookup_qualified_name ( - inst, get_identifier ("index_type"), true, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) - throw operation_failed (); - - tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); - it = &dynamic_cast (*unit.find (type)); - - // Find the hint. - // - for (tree ot (DECL_ORIGINAL_TYPE (decl)); - ot != 0; - ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0) - { - if ((ih = unit.find_hint (ot))) - break; - - decl = TYPE_NAME (ot); - } - } - catch (operation_failed const&) - { - os << f << ":" << l << ":" << c << ": error: " - << "container_traits specialization does not define the " - << "index_type type" << endl; - - throw; - } - - t.set ("index-tree-type", it); - t.set ("index-tree-hint", ih); - t.set ("index-not-null", true); - } - - // Get the key type for maps. - // - if (ck == ck_map || ck == ck_multimap) - { - try - { - tree decl ( - lookup_qualified_name ( - inst, get_identifier ("key_type"), true, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) - throw operation_failed (); - - tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); - kt = &dynamic_cast (*unit.find (type)); - - // Find the hint. - // - for (tree ot (DECL_ORIGINAL_TYPE (decl)); - ot != 0; - ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0) - { - if ((kh = unit.find_hint (ot))) - break; - - decl = TYPE_NAME (ot); - } - } - catch (operation_failed const&) - { - os << f << ":" << l << ":" << c << ": error: " - << "container_traits specialization does not define the " - << "key_type type" << endl; - - throw; - } - - t.set ("key-tree-type", kt); - t.set ("key-tree-hint", kh); - t.set ("key-not-null", true); - } + if (ck == ck_map || ck == ck_multimap) + { + kt = t.get ("key-tree-type"); + kh = t.get ("key-tree-hint"); } // Process member data. // - m.set ("id-tree-type", &id_tree_type); m.set ("id-column-type", &id_column_type); process_container_value (*vt, vh, m, "value", true); @@ -744,562 +401,7 @@ namespace relational if (kt != 0) process_container_value (*kt, kh, m, "key", false); - - // If this is an inverse side of a bidirectional object relationship - // and it is an ordered container, mark it as unordred since there is - // no concept of order in this construct. - // - if (ck == ck_ordered && m.count ("value-inverse")) - m.set ("unordered", true); - - // Issue an error if we have a null column in a set container. - // This can only happen if the value is declared as null in - // the member. - // - if (ck == ck_set && m.count ("value-null")) - { - os << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " error: set container cannot contain null values" << endl; - - throw operation_failed (); - } - - // Issue a warning if we are relaxing null-ness in the member. - // - if (m.count ("value-null") && - (t.count ("value-not-null") || vt->count ("not-null"))) - { - os << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " warning: container value declared null while the container " - << "type or value type declares it as not null" << endl; - } - - return true; } - - semantics::class_* - process_object_pointer (semantics::data_member& m, - semantics::type& t, - string const& kp = string ()) - { - // The overall idea is as follows: try to instantiate the pointer - // traits class template. If we are successeful, then get the - // element type and see if it is an object. - // - using semantics::class_; - using semantics::data_member; - - class_* c (0); - - if (t.count ("element-type")) - c = t.get ("element-type"); - else - { - tree inst (instantiate_template (pointer_traits_, t.tree_node ())); - - if (inst == 0) - return 0; - - // @@ This points to the primary template, not the specialization. - // - tree decl (TYPE_NAME (inst)); - - string fl (DECL_SOURCE_FILE (decl)); - size_t ln (DECL_SOURCE_LINE (decl)); - size_t cl (DECL_SOURCE_COLUMN (decl)); - - // Get the element type. - // - tree tn (0); - try - { - tree decl ( - lookup_qualified_name ( - inst, get_identifier ("element_type"), true, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) - throw operation_failed (); - - tn = TYPE_MAIN_VARIANT (TREE_TYPE (decl)); - - // Check if the pointer is a TR1 template instantiation. - // - if (tree ti = TYPE_TEMPLATE_INFO (t.tree_node ())) - { - decl = TI_TEMPLATE (ti); // DECL_TEMPLATE - - // Get to the most general template declaration. - // - while (DECL_TEMPLATE_INFO (decl)) - decl = DECL_TI_TEMPLATE (decl); - - bool& tr1 (features.tr1_pointer); - bool& boost (features.boost_pointer); - - 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; - } - } - catch (operation_failed const&) - { - os << fl << ":" << ln << ":" << cl << ": error: pointer_traits " - << "specialization does not define the 'element_type' type" - << endl; - throw; - } - - c = dynamic_cast (unit.find (tn)); - - if (c == 0 || !object (*c)) - return 0; - - t.set ("element-type", c); - - // Determine the pointer kind. - // - try - { - tree kind ( - lookup_qualified_name ( - inst, get_identifier ("kind"), false, false)); - - if (kind == error_mark_node || TREE_CODE (kind) != VAR_DECL) - throw operation_failed (); - - // Instantiate this decalaration so that we can get its value. - // - if (DECL_TEMPLATE_INSTANTIATION (kind) && - !DECL_TEMPLATE_INSTANTIATED (kind) && - !DECL_EXPLICIT_INSTANTIATION (kind)) - instantiate_decl (kind, false, false); - - tree init (DECL_INITIAL (kind)); - - if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) - throw operation_failed (); - - unsigned long long e; - - { - HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); - HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); - - unsigned long long l (hwl); - unsigned long long h (hwh); - unsigned short width (HOST_BITS_PER_WIDE_INT); - - e = (h << width) + l; - } - - pointer_kind_type pk = static_cast (e); - t.set ("pointer-kind", pk); - } - catch (operation_failed const&) - { - os << fl << ":" << ln << ":" << cl << ": error: pointer_traits " - << "specialization does not define the 'kind' constant" << endl; - throw; - } - - // Get the lazy flag. - // - try - { - tree lazy ( - lookup_qualified_name ( - inst, get_identifier ("lazy"), false, false)); - - if (lazy == error_mark_node || TREE_CODE (lazy) != VAR_DECL) - throw operation_failed (); - - // Instantiate this decalaration so that we can get its value. - // - if (DECL_TEMPLATE_INSTANTIATION (lazy) && - !DECL_TEMPLATE_INSTANTIATED (lazy) && - !DECL_EXPLICIT_INSTANTIATION (lazy)) - instantiate_decl (lazy, false, false); - - tree init (DECL_INITIAL (lazy)); - - if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) - throw operation_failed (); - - unsigned long long e; - - { - HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); - HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); - - unsigned long long l (hwl); - unsigned long long h (hwh); - unsigned short width (HOST_BITS_PER_WIDE_INT); - - e = (h << width) + l; - } - - t.set ("pointer-lazy", static_cast (e)); - } - catch (operation_failed const&) - { - os << fl << ":" << ln << ":" << cl << ": error: pointer_traits " - << "specialization does not define the 'kind' constant" << endl; - throw; - } - } - - // Make sure the pointed-to class is complete. - // - if (!c->complete ()) - { - os << m.file () << ":" << m.line () << ":" << m.column () << ": " - << "error: pointed-to class '" << class_fq_name (*c) << "' " - << "is incomplete" << endl; - - os << c->file () << ":" << c->line () << ":" << c->column () << ": " - << "info: class '" << class_name (*c) << "' is declared here" - << endl; - - os << c->file () << ":" << c->line () << ":" << c->column () << ": " - << "info: consider including its definition with the " - << "--odb-epilogue option" << endl; - - throw operation_failed (); - } - - // Make sure the pointed-to class is not reuse-abstract. - // - if (abstract (*c) && !polymorphic (*c)) - { - os << m.file () << ":" << m.line () << ":" << m.column () << ": " - << "error: pointed-to class '" << class_fq_name (*c) << "' " - << "is abstract" << endl; - - os << c->file () << ":" << c->line () << ":" << c->column () << ": " - << "info: class '" << class_name (*c) << "' is defined here" - << endl; - - throw operation_failed (); - } - - // Make sure the pointed-to class has object id. - // - if (id_member (*c) == 0) - { - os << m.file () << ":" << m.line () << ":" << m.column () << ": " - << "error: pointed-to class '" << class_fq_name (*c) << "' " - << "has no object id" << endl; - - os << c->file () << ":" << c->line () << ":" << c->column () << ": " - << "info: class '" << class_name (*c) << "' is defined here" - << endl; - - throw operation_failed (); - } - - // See if this is the inverse side of a bidirectional relationship. - // If so, then resolve the member and cache it in the context. - // - if (m.count ("inverse")) - { - string name (m.get ("inverse")); - location_t loc (m.get ("inverse-location")); - - try - { - data_member& im ( - c->lookup (name, class_::include_hidden)); - - // @@ Would be good to check that the other end is actually - // an object pointer, is not marked as transient or inverse, - // and points to the correct object. But the other class may - // not have been processed yet. - // - m.remove ("inverse"); - m.set (kp + (kp.empty () ? "": "-") + "inverse", &im); - } - catch (semantics::unresolved const& e) - { - if (e.type_mismatch) - error (loc) << "name '" << name << "' in '#pragma db " << - "inverse' does not refer to a data member" << endl; - else - error (loc) << "unable to resolve data member '" << name << - "' specified with '#pragma db inverse'" << endl; - - throw operation_failed (); - } - catch (semantics::ambiguous const& e) - { - error (loc) << "data member name '" << name << "' specified " << - "with '#pragma db inverse' is ambiguous" << endl; - - info (e.first.named ().location ()) << "could resolve to this " << - "data member" << endl; - - info (e.second.named ().location ()) << "or could resolve to " << - "this data member" << endl; - - throw operation_failed (); - } - } - - return c; - } - - bool - process_wrapper (semantics::type& t) - { - if (t.count ("wrapper")) - return t.get ("wrapper"); - - // Check this type with wrapper_traits. - // - tree inst (instantiate_template (wrapper_traits_, t.tree_node ())); - - if (inst == 0) - { - t.set ("wrapper", false); - return false; - } - - // @@ This points to the primary template, not the specialization. - // - tree decl (TYPE_NAME (inst)); - - string f (DECL_SOURCE_FILE (decl)); - size_t l (DECL_SOURCE_LINE (decl)); - size_t c (DECL_SOURCE_COLUMN (decl)); - - // Get the wrapped type. - // - try - { - tree decl ( - lookup_qualified_name ( - inst, get_identifier ("wrapped_type"), true, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) - throw operation_failed (); - - // The wrapped_type alias is a typedef in an instantiation - // that we just instantiated dynamically. As a result there - // is no semantic graph edges corresponding to this typedef - // since we haven't parsed it yet. So to get the tree node - // that can actually be resolved to the graph node, we use - // the source type of this typedef. - // - tree type (DECL_ORIGINAL_TYPE (decl)); - - semantics::type& wt ( - dynamic_cast (*unit.find (type))); - - // Find the hint. - // - semantics::names* wh (0); - - for (tree ot (DECL_ORIGINAL_TYPE (decl)); - ot != 0; - ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0) - { - if ((wh = unit.find_hint (ot))) - break; - - decl = TYPE_NAME (ot); - } - - t.set ("wrapper-type", &wt); - t.set ("wrapper-hint", wh); - } - catch (operation_failed const&) - { - os << f << ":" << l << ":" << c << ": error: " - << "wrapper_traits specialization does not define the " - << "wrapped_type type" << endl; - throw; - } - - // Get the null_handler flag. - // - bool null_handler (false); - - try - { - tree nh ( - lookup_qualified_name ( - inst, get_identifier ("null_handler"), false, false)); - - if (nh == error_mark_node || TREE_CODE (nh) != VAR_DECL) - throw operation_failed (); - - // Instantiate this decalaration so that we can get its value. - // - if (DECL_TEMPLATE_INSTANTIATION (nh) && - !DECL_TEMPLATE_INSTANTIATED (nh) && - !DECL_EXPLICIT_INSTANTIATION (nh)) - instantiate_decl (nh, false, false); - - tree init (DECL_INITIAL (nh)); - - if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) - throw operation_failed (); - - unsigned long long e; - - { - HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); - HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); - - unsigned long long l (hwl); - unsigned long long h (hwh); - unsigned short width (HOST_BITS_PER_WIDE_INT); - - e = (h << width) + l; - } - - null_handler = static_cast (e); - t.set ("wrapper-null-handler", null_handler); - } - catch (operation_failed const&) - { - os << f << ":" << l << ":" << c << ": error: " - << "wrapper_traits specialization does not define the " - << "null_handler constant" << endl; - throw; - } - - // Get the null_default flag. - // - if (null_handler) - { - try - { - tree nh ( - lookup_qualified_name ( - inst, get_identifier ("null_default"), false, false)); - - if (nh == error_mark_node || TREE_CODE (nh) != VAR_DECL) - throw operation_failed (); - - // Instantiate this decalaration so that we can get its value. - // - if (DECL_TEMPLATE_INSTANTIATION (nh) && - !DECL_TEMPLATE_INSTANTIATED (nh) && - !DECL_EXPLICIT_INSTANTIATION (nh)) - instantiate_decl (nh, false, false); - - tree init (DECL_INITIAL (nh)); - - if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) - throw operation_failed (); - - unsigned long long e; - - { - HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); - HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); - - unsigned long long l (hwl); - unsigned long long h (hwh); - unsigned short width (HOST_BITS_PER_WIDE_INT); - - e = (h << width) + l; - } - - t.set ("wrapper-null-default", static_cast (e)); - } - catch (operation_failed const&) - { - os << f << ":" << l << ":" << c << ": error: " - << "wrapper_traits specialization does not define the " - << "null_default constant" << endl; - throw; - } - } - - // Check if the wrapper is a TR1 template instantiation. - // - if (tree ti = TYPE_TEMPLATE_INFO (t.tree_node ())) - { - tree decl (TI_TEMPLATE (ti)); // DECL_TEMPLATE - - // Get to the most general template declaration. - // - while (DECL_TEMPLATE_INFO (decl)) - decl = DECL_TI_TEMPLATE (decl); - - bool& tr1 (features.tr1_pointer); - bool& boost (features.boost_pointer); - - 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; - } - - t.set ("wrapper", true); - return true; - } - - tree - instantiate_template (tree t, tree arg) - { - tree args (make_tree_vec (1)); - TREE_VEC_ELT (args, 0) = arg; - - // This step should succeed regardles of whether there is a - // specialization for this type. - // - tree inst ( - lookup_template_class (t, args, 0, 0, 0, tf_warning_or_error)); - - if (inst == error_mark_node) - { - // Diagnostics has already been issued by lookup_template_class. - // - throw operation_failed (); - } - - inst = TYPE_MAIN_VARIANT (inst); - - // The instantiation may already be complete if it matches a - // (complete) specialization or was used before. - // - if (!COMPLETE_TYPE_P (inst)) - inst = instantiate_class_template (inst); - - // If we cannot instantiate this type, assume there is no suitable - // specialization for it. - // - if (inst == error_mark_node || !COMPLETE_TYPE_P (inst)) - return 0; - - return inst; - } - - private: - tree wrapper_traits_; - tree pointer_traits_; - tree container_traits_; }; // @@ -2151,19 +1253,10 @@ namespace relational throw operation_failed (); } - // Resolve referenced objects from tree nodes to semantic graph - // nodes. + // Process join conditions. // - 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_; - view_objects& objs (c.get ("objects")); for (view_objects::iterator i (objs.begin ()); i != objs.end (); ++i) @@ -2181,94 +1274,8 @@ namespace relational throw operation_failed (); } - tbl_count++; continue; } - else - obj_count++; - - tree n (TYPE_MAIN_VARIANT (i->obj_node)); - - if (TREE_CODE (n) != RECORD_TYPE) - { - error (i->loc) - << "name '" << i->obj_name << "' in db pragma object does " - << "not name a class" << endl; - - throw operation_failed (); - } - - class_& o (dynamic_cast (*unit.find (n))); - - if (!object (o)) - { - error (i->loc) - << "name '" << i->obj_name << "' in db pragma object does " - << "not name a persistent class" << endl; - - info (o.file (), o.line (), o.column ()) - << "class '" << i->obj_name << "' is defined here" << endl; - - throw operation_failed (); - } - - i->obj = &o; - - if (i->alias.empty ()) - { - if (!omap.insert (view_object_map::value_type (&o, &*i)).second) - { - error (i->loc) << "persistent class '" << i->obj_name << - "' is used in the view more than once" << endl; - - error (omap[&o]->loc) << "previously used here" << endl; - - info (i->loc) << "use the alias clause to assign it a " << - "different name" << endl; - - throw operation_failed (); - } - - // Also add the bases of a polymorphic object. - // - class_* poly_root (polymorphic (o)); - - if (poly_root != 0 && poly_root != &o) - { - for (class_* b (&polymorphic_base (o));; - b = &polymorphic_base (*b)) - { - if (!omap.insert ( - view_object_map::value_type (b, &*i)).second) - { - error (i->loc) << "base class '" << class_name (*b) << - "' is used in the view more than once" << endl; - - error (omap[b]->loc) << "previously used here" << endl; - - info (i->loc) << "use the alias clause to assign it a " << - "different name" << endl; - - throw operation_failed (); - } - - if (b == poly_root) - break; - } - } - } - else - { - if (!amap.insert ( - view_alias_map::value_type (i->alias, &*i)).second) - { - error (i->loc) - << "alias '" << i->alias << "' is used in the view more " - << "than once" << endl; - - throw operation_failed (); - } - } // If we have to generate the query and there was no JOIN // condition specified by the user, try to come up with one -- cgit v1.1