aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/context.cxx18
-rw-r--r--odb/context.hxx15
-rw-r--r--odb/option-types.cxx16
-rw-r--r--odb/option-types.hxx5
-rw-r--r--odb/plugin.cxx1
-rw-r--r--odb/pragma.cxx110
-rw-r--r--odb/pragma.hxx11
-rw-r--r--odb/processor.cxx1115
-rw-r--r--odb/relational/processor.cxx1067
9 files changed, 1264 insertions, 1094 deletions
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<bool> ("wrapper"))
+ {
+ hint = t.get<semantics::names*> ("wrapper-hint");
+ return t.get<semantics::type*> ("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 <typename X>
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<declaration, pragma_set> 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<std::string> 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<semantics::type*> ("wrapper-type");
+ whint = t.get<semantics::names*> ("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<const T> - can modify by setting a new pointer
+ // const auto_ptr<T> - 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<char>) 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,6 +586,933 @@ namespace
}
}
}
+
+ //
+ // Process wrapper.
+ //
+
+ bool
+ process_wrapper (semantics::type& t)
+ {
+ if (t.count ("wrapper"))
+ return t.get<bool> ("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<semantics::type&> (*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<bool> (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<bool> (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;
+ }
+
+ //
+ // Process object pointer.
+ //
+
+ 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<class_*> ("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<class_*> (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<pointer_kind_type> (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<bool> (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<string> ("inverse"));
+ location_t loc (m.get<location_t> ("inverse-location"));
+
+ try
+ {
+ data_member& im (
+ c->lookup<data_member> (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_type> ("container-kind");
+ vt = t.get<semantics::type*> ("value-tree-type");
+ vh = t.get<semantics::names*> ("value-tree-hint");
+
+ if (ck == ck_ordered)
+ {
+ it = t.get<semantics::type*> ("index-tree-type");
+ ih = t.get<semantics::names*> ("index-tree-hint");
+ }
+
+ if (ck == ck_map || ck == ck_multimap)
+ {
+ kt = t.get<semantics::type*> ("key-tree-type");
+ kh = t.get<semantics::names*> ("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<container_kind_type> (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<semantics::type&> (*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<semantics::type&> (*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<semantics::type&> (*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
@@ -583,6 +1578,8 @@ namespace
if (k == class_object)
traverse_object (c);
+ else if (k == class_view)
+ traverse_view (c);
names (c);
}
@@ -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<view_objects> ("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<class_&> (*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<semantics::type*> ("wrapper-type");
- whint = t.get<semantics::names*> ("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<const T> - can modify by setting a new pointer
- // const auto_ptr<T> - 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<semantics::names*> ("wrapper-hint");
- wt = &utype (*idt.get<semantics::type*> ("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<string> ("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<semantics::type*> ("wrapper-type");
- wh = t.get<semantics::names*> ("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<string> (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<semantics::names*> ("wrapper-hint");
- wt = &utype (*idt.get<semantics::type*> ("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<string> ("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_type> ("container-kind"));
+ semantics::type* vt (t.get<semantics::type*> ("value-tree-type"));
semantics::type* it (0);
semantics::type* kt (0);
- semantics::names* vh (0);
+ semantics::names* vh (t.get<semantics::names*> ("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_type> ("container-kind");
- vt = t.get<semantics::type*> ("value-tree-type");
- vh = t.get<semantics::names*> ("value-tree-hint");
-
- if (ck == ck_ordered)
- {
- it = t.get<semantics::type*> ("index-tree-type");
- ih = t.get<semantics::names*> ("index-tree-hint");
- }
-
- if (ck == ck_map || ck == ck_multimap)
- {
- kt = t.get<semantics::type*> ("key-tree-type");
- kh = t.get<semantics::names*> ("key-tree-hint");
- }
+ it = t.get<semantics::type*> ("index-tree-type");
+ ih = t.get<semantics::names*> ("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<container_kind_type> (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<semantics::type&> (*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<semantics::type&> (*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<semantics::type&> (*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<semantics::type*> ("key-tree-type");
+ kh = t.get<semantics::names*> ("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<class_*> ("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<class_*> (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<pointer_kind_type> (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<bool> (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<string> ("inverse"));
- location_t loc (m.get<location_t> ("inverse-location"));
-
- try
- {
- data_member& im (
- c->lookup<data_member> (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<bool> ("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<semantics::type&> (*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<bool> (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<bool> (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<view_objects> ("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<class_&> (*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