summaryrefslogtreecommitdiff
path: root/odb/relational
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-08-15 11:46:00 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-08-15 11:46:00 +0200
commiteacf52a9a4f3832274fdefc909ab23c13413e128 (patch)
treef1f754b6149797315f91d6f872363555201d5a65 /odb/relational
parent396cad633b6f0559a39e5111827f9b1125c67506 (diff)
Add support for member accessors/modifiers
New pragmas: get, set, access. New test: common/access.
Diffstat (limited to 'odb/relational')
-rw-r--r--odb/relational/inline.hxx18
-rw-r--r--odb/relational/mssql/source.cxx35
-rw-r--r--odb/relational/oracle/source.cxx39
-rw-r--r--odb/relational/processor.cxx432
-rw-r--r--odb/relational/source.cxx339
-rw-r--r--odb/relational/source.hxx379
6 files changed, 939 insertions, 303 deletions
diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx
index 39801cb..2642809 100644
--- a/odb/relational/inline.hxx
+++ b/odb/relational/inline.hxx
@@ -5,6 +5,7 @@
#ifndef ODB_RELATIONAL_INLINE_HXX
#define ODB_RELATIONAL_INLINE_HXX
+#include <odb/diagnostics.hxx>
#include <odb/relational/context.hxx>
#include <odb/relational/common.hxx>
@@ -258,16 +259,27 @@ namespace relational
os << "inline" << endl
<< traits << "::id_type" << endl
<< traits << "::" << endl
- << "id (const object_type&" << (id != 0 ? " obj" : "") << ")"
+ << "id (const object_type&" << (id != 0 ? " o" : "") << ")"
<< "{";
if (id != 0)
{
if (base_id)
os << "return object_traits< " << class_fq_name (*base) <<
- " >::id (obj);";
+ " >::id (o);";
else
- os << "return obj." << id->name () << ";";
+ {
+ // Get the id using the accessor expression. If this is not
+ // a synthesized expression, then output its location for
+ // easier error tracking.
+ //
+ member_access& ma (id->get<member_access> ("get"));
+
+ if (ma.loc != 0)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ os << "return " << ma.translate ("o") << ";";
+ }
}
os << "}";
diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx
index 1201c87..7fce155 100644
--- a/odb/relational/mssql/source.cxx
+++ b/odb/relational/mssql/source.cxx
@@ -307,6 +307,24 @@ namespace relational
}
virtual void
+ check_accessor (member_info& mi, member_access& ma)
+ {
+ // We cannot use accessors that return by-value for long data
+ // members.
+ //
+ if (long_data (*mi.st) && ma.by_value)
+ {
+ error (ma.loc) << "accessor returning a value cannot be used "
+ << "for a data member of SQL Server long data "
+ << "type" << endl;
+ info (ma.loc) << "accessor returning a const reference is required"
+ << endl;
+ info (mi.m.location ()) << "data member is defined here" << endl;
+ throw operation_failed ();
+ }
+ }
+
+ virtual void
traverse_integer (member_info& mi)
{
os << traits << "::set_image (" << endl
@@ -541,6 +559,23 @@ namespace relational
}
virtual void
+ check_modifier (member_info& mi, member_access& ma)
+ {
+ // We cannot use by-value modifier for long data members.
+ //
+ if (long_data (*mi.st) && ma.placeholder ())
+ {
+ error (ma.loc) << "modifier accepting a value cannot be used "
+ << "for a data member of SQL Server long data "
+ << "type" << endl;
+ info (ma.loc) << "modifier returning a non-const reference is "
+ << "required" << endl;
+ info (mi.m.location ()) << "data member is defined here" << endl;
+ throw operation_failed ();
+ }
+ }
+
+ virtual void
traverse_integer (member_info& mi)
{
os << traits << "::set_value (" << endl
diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx
index 780dc06..85be6cc 100644
--- a/odb/relational/oracle/source.cxx
+++ b/odb/relational/oracle/source.cxx
@@ -217,6 +217,26 @@ namespace relational
}
virtual void
+ check_accessor (member_info& mi, member_access& ma)
+ {
+ // We cannot use accessors that return by-value for LOB
+ // members.
+ //
+ if ((mi.st->type == sql_type::BLOB ||
+ mi.st->type == sql_type::CLOB ||
+ mi.st->type == sql_type::NCLOB) &&
+ ma.by_value)
+ {
+ error (ma.loc) << "accessor returning a value cannot be used "
+ << "for a data member of Oracle LOB type" << endl;
+ info (ma.loc) << "accessor returning a const reference is required"
+ << endl;
+ info (mi.m.location ()) << "data member is defined here" << endl;
+ throw operation_failed ();
+ }
+ }
+
+ virtual void
set_null (member_info& mi)
{
os << "i." << mi.var << "indicator = -1;";
@@ -363,6 +383,25 @@ namespace relational
}
virtual void
+ check_modifier (member_info& mi, member_access& ma)
+ {
+ // We cannot use by-value modifier for LOB members.
+ //
+ if ((mi.st->type == sql_type::BLOB ||
+ mi.st->type == sql_type::CLOB ||
+ mi.st->type == sql_type::NCLOB) &&
+ ma.placeholder ())
+ {
+ error (ma.loc) << "modifier accepting a value cannot be used "
+ << "for a data member of Oracle LOB type" << endl;
+ info (ma.loc) << "modifier returning a non-const reference is "
+ << "required" << endl;
+ info (mi.m.location ()) << "data member is defined here" << endl;
+ throw operation_failed ();
+ }
+ }
+
+ virtual void
traverse_int32 (member_info& mi)
{
os << traits << "::set_value (" << endl
diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx
index 64987a2..7e2bf53 100644
--- a/odb/relational/processor.cxx
+++ b/odb/relational/processor.cxx
@@ -120,8 +120,6 @@ namespace relational
if (transient (m))
return;
- process_index (m);
-
semantics::names* hint;
semantics::type& t (utype (m, hint));
@@ -151,146 +149,378 @@ namespace relational
m.set ("readonly", true);
}
- // Nothing to do if this is a composite value type.
+ // Determine the member kind.
//
- if (composite_wrapper (t))
- return;
-
- string type, id_type;
+ enum {simple, composite, container, unknown} kind (unknown);
- if (m.count ("id-type"))
- id_type = m.get<string> ("id-type");
+ // See if this is a composite value type.
+ //
+ if (composite_wrapper (t))
+ kind = composite;
- if (m.count ("type"))
+ // If not, see if it is a simple value.
+ //
+ if (kind == unknown)
{
- type = m.get<string> ("type");
+ string type, id_type;
- if (id_type.empty ())
- id_type = type;
- }
+ if (m.count ("id-type"))
+ id_type = m.get<string> ("id-type");
- if (semantics::class_* c = process_object_pointer (m, t))
- {
- // This is an object pointer. The column type is the pointed-to
- // object id type.
- //
- semantics::data_member& id (*id_member (*c));
+ if (m.count ("type"))
+ {
+ type = m.get<string> ("type");
- semantics::names* idhint;
- semantics::type& idt (utype (id, idhint));
+ if (id_type.empty ())
+ id_type = type;
+ }
- semantics::type* wt (0);
- semantics::names* whint (0);
- if (process_wrapper (idt))
+ if (semantics::class_* c = process_object_pointer (m, t))
{
- whint = idt.get<semantics::names*> ("wrapper-hint");
- wt = &utype (*idt.get<semantics::type*> ("wrapper-type"), whint);
+ // This is an object pointer. The column type is the pointed-to
+ // object id type.
+ //
+ semantics::data_member& id (*id_member (*c));
+
+ 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
+ {
+ if (type.empty () && id.count ("id-type"))
+ type = id.get<string> ("id-type");
+
+ if (type.empty () && id.count ("type"))
+ type = id.get<string> ("type");
+
+ // The rest should be identical to the code for the id_type in
+ // the else block.
+ //
+ if (type.empty () && idt.count ("id-type"))
+ type = idt.get<string> ("id-type");
+
+ if (type.empty () && wt != 0 && wt->count ("id-type"))
+ type = wt->get<string> ("id-type");
+
+ if (type.empty () && idt.count ("type"))
+ type = idt.get<string> ("type");
+
+ if (type.empty () && wt != 0 && wt->count ("type"))
+ type = wt->get<string> ("type");
+
+ if (type.empty ())
+ type = database_type (idt, idhint, true);
+
+ if (type.empty () && wt != 0)
+ type = database_type (*wt, whint, true);
+
+ id_type = type;
+ }
}
+ else
+ {
+ if (id_type.empty () && t.count ("id-type"))
+ id_type = t.get<string> ("id-type");
- // Nothing to do if this is a composite value type.
- //
- if (composite_wrapper (idt))
- return;
+ if (id_type.empty () && wt != 0 && wt->count ("id-type"))
+ id_type = wt->get<string> ("id-type");
- if (type.empty () && id.count ("id-type"))
- type = id.get<string> ("id-type");
+ if (type.empty () && t.count ("type"))
+ type = t.get<string> ("type");
- if (type.empty () && id.count ("type"))
- type = id.get<string> ("type");
+ if (type.empty () && wt != 0 && wt->count ("type"))
+ type = wt->get<string> ("type");
- // The rest should be identical to the code for the id_type in
- // the else block.
- //
- if (type.empty () && idt.count ("id-type"))
- type = idt.get<string> ("id-type");
+ if (id_type.empty ())
+ id_type = type;
- if (type.empty () && wt != 0 && wt->count ("id-type"))
- type = wt->get<string> ("id-type");
+ if (id_type.empty ())
+ id_type = database_type (t, hint, true);
- if (type.empty () && idt.count ("type"))
- type = idt.get<string> ("type");
+ if (type.empty ())
+ type = database_type (t, hint, false);
- if (type.empty () && wt != 0 && wt->count ("type"))
- type = wt->get<string> ("type");
+ if (id_type.empty () && wt != 0)
+ id_type = database_type (*wt, whint, true);
- if (type.empty ())
- type = database_type (idt, idhint, true);
+ if (type.empty () && wt != 0)
+ type = database_type (*wt, whint, false);
- if (type.empty () && wt != 0)
- type = database_type (*wt, whint, true);
+ // Use id mapping for discriminators.
+ //
+ if (id (m) || discriminator (m))
+ type = id_type;
+ }
+
+ if (kind == unknown && !type.empty ())
+ {
+ m.set ("column-type", type);
+ m.set ("column-id-type", id_type);
+
+ // Issue a warning if we are relaxing null-ness.
+ //
+ if (m.count ("null") && t.count ("not-null"))
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " warning: data member declared null while its type is "
+ << "declared not null" << endl;
+ }
- id_type = type;
+ kind = simple;
+ }
}
- else
+
+ // If not a simple value, see if this is a container.
+ //
+ if (kind == unknown &&
+ (process_container (m, t) ||
+ (wt != 0 && process_container (m, *wt))))
+ kind = container;
+
+ // If it is none of the above then we have an error.
+ //
+ if (kind == unknown)
{
- if (id_type.empty () && t.count ("id-type"))
- id_type = t.get<string> ("id-type");
+ 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;
- if (id_type.empty () && wt != 0 && wt->count ("id-type"))
- id_type = wt->get<string> ("id-type");
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " info: use '#pragma db type' to specify the database type"
+ << endl;
- if (type.empty () && t.count ("type"))
- type = t.get<string> ("type");
+ throw operation_failed ();
+ }
- if (type.empty () && wt != 0 && wt->count ("type"))
- type = wt->get<string> ("type");
+ process_access (m, "get");
+ process_access (m, "set");
+ process_index (m);
+ }
- if (id_type.empty ())
- id_type = type;
+ // Process member access expressions.
+ //
+ void
+ process_access (semantics::data_member& m, std::string const& k)
+ {
+ // If we don't have an access expression, synthesize one which
+ // goes directly for the member. Zero location indicates it is
+ // a synthesized one.
+ //
+ if (!m.count (k))
+ {
+ member_access& ma (m.set (k, member_access (0)));
+ ma.expr.push_back (cxx_token (0, CPP_KEYWORD, "this"));
+ ma.expr.push_back (cxx_token (0, CPP_DOT));
+ ma.expr.push_back (cxx_token (0, CPP_NAME, m.name ()));
+ return;
+ }
- if (id_type.empty ())
- id_type = database_type (t, hint, true);
+ semantics::type& t (utype (m));
+ member_access& ma (m.get<member_access> (k));
+ cxx_tokens& e (ma.expr);
- if (type.empty ())
- type = database_type (t, hint, false);
+ // If it is just a name, resolve it and convert to an
+ // appropriate expression.
+ //
+ if (e.size () == 1 && e.back ().type == CPP_NAME)
+ {
+ string n (e.back ().literal);
+ e.clear ();
- if (id_type.empty () && wt != 0)
- id_type = database_type (*wt, whint, true);
+ tree decl (
+ lookup_qualified_name (
+ m.scope ().tree_node (),
+ get_identifier (n.c_str ()),
+ false,
+ false));
- if (type.empty () && wt != 0)
- type = database_type (*wt, whint, false);
+ if (decl == error_mark_node)
+ {
+ error (ma.loc) << "unable to resolve data member or function "
+ << "name '" << n << "'" << endl;
+ throw operation_failed ();
+ }
- // Use id mapping for discriminators.
- //
- if (id (m) || discriminator (m))
- type = id_type;
+ switch (TREE_CODE (decl))
+ {
+ case FIELD_DECL:
+ {
+ e.push_back (cxx_token (0, CPP_KEYWORD, "this"));
+ e.push_back (cxx_token (0, CPP_DOT));
+ e.push_back (cxx_token (0, CPP_NAME, n));
+ break;
+ }
+ case BASELINK:
+ {
+ // OVL_* macros work for both FUNCTION_DECL and OVERLOAD.
+ //
+ for (tree o (BASELINK_FUNCTIONS (decl));
+ o != 0;
+ o = OVL_NEXT (o))
+ {
+ tree f (OVL_CURRENT (o));
+
+ // We are only interested in non-static member functions.
+ //
+ if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (f))
+ continue;
+
+ // Note that we have to use TREE_TYPE(TREE_TYPE()) and
+ // not DECL_RESULT, as suggested by the documentation.
+ //
+ tree r (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (f))));
+ tree a (DECL_ARGUMENTS (f));
+ a = DECL_CHAIN (a); // Skip this.
+
+ if (k == "get")
+ {
+ // For an accessor, look for a function with a non-void
+ // return value and no arguments (other than 'this').
+ //
+ if (r != void_type_node && a == NULL_TREE)
+ {
+ e.push_back (cxx_token (0, CPP_KEYWORD, "this"));
+ e.push_back (cxx_token (0, CPP_DOT));
+ e.push_back (cxx_token (0, CPP_NAME, n));
+ e.push_back (cxx_token (0, CPP_OPEN_PAREN, n));
+ e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n));
+
+ // See if it returns by value.
+ //
+ int tc (TREE_CODE (r));
+ ma.by_value = (tc != REFERENCE_TYPE && tc != POINTER_TYPE);
+ break;
+ }
+ }
+ else
+ {
+ // For a modifier, it can either be a function that
+ // returns a non-const reference (or non-const pointer,
+ // in case the member is an array) or a proper modifier
+ // that sets a new value. If both are available, we
+ // prefer the former for efficiency.
+ //
+ semantics::array* ar (dynamic_cast<semantics::array*> (&t));
+ int tc (TREE_CODE (r));
+
+ if (a == NULL_TREE &&
+ ((ar == 0 && tc == REFERENCE_TYPE) ||
+ (ar != 0 && tc == POINTER_TYPE)))
+ {
+ tree bt (TREE_TYPE (r)); // Base type.
+ tree bt_mv (TYPE_MAIN_VARIANT (bt));
+
+ if (!CP_TYPE_CONST_P (bt) &&
+ ((ar == 0 && bt_mv == t.tree_node ()) ||
+ (ar != 0 && bt_mv == ar->base_type ().tree_node ())))
+ {
+ e.clear (); // Could contain proper modifier.
+ e.push_back (cxx_token (0, CPP_KEYWORD, "this"));
+ e.push_back (cxx_token (0, CPP_DOT));
+ e.push_back (cxx_token (0, CPP_NAME, n));
+ e.push_back (cxx_token (0, CPP_OPEN_PAREN, n));
+ e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n));
+ break;
+ }
+ }
+
+ // Any function with a single argument works for us.
+ // And we don't care what it returns.
+ //
+ if (a != NULL_TREE && DECL_CHAIN (a) == NULL_TREE)
+ {
+ if (e.empty ())
+ {
+ e.push_back (cxx_token (0, CPP_KEYWORD, "this"));
+ e.push_back (cxx_token (0, CPP_DOT));
+ e.push_back (cxx_token (0, CPP_NAME, n));
+ e.push_back (cxx_token (0, CPP_OPEN_PAREN, n));
+ e.push_back (cxx_token (0, CPP_QUERY));
+ e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n));
+ }
+
+ // Continue searching in case there is version that
+ // returns a non-const reference (which we prefer).
+ }
+ }
+ }
+
+ if (e.empty ())
+ {
+ error (ma.loc) << "unable to find suitable "
+ << (k == "get" ? "accessor" : "modifier")
+ << " function '" << n << "'" << endl;
+ throw operation_failed ();
+ }
+ break;
+ }
+ default:
+ {
+ error (ma.loc) << "name '" << n << "' does not refer to a data "
+ << "member or function" << endl;
+ throw operation_failed ();
+ }
+ }
}
- if (!type.empty ())
+ // If there is no 'this' keyword, then add it as a prefix.
+ //
{
- m.set ("column-type", type);
- m.set ("column-id-type", id_type);
-
- // Issue a warning if we are relaxing null-ness.
- //
- if (m.count ("null") && t.count ("not-null"))
+ bool t (false);
+ for (cxx_tokens::iterator i (e.begin ()); i != e.end (); ++i)
{
- os << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " warning: data member declared null while its type is "
- << "declared not null" << endl;
+ if (i->type == CPP_KEYWORD && i->literal == "this")
+ {
+ t = true;
+ break;
+ }
}
- return;
+ if (!t)
+ {
+ e.insert (e.begin (), cxx_token (0, CPP_DOT));
+ e.insert (e.begin (), cxx_token (0, CPP_KEYWORD, "this"));
+ }
}
- // See if this is a container type.
+ // Check that there is no placeholder in the accessor expression.
//
- if (process_container (m, t) ||
- (wt != 0 && process_container (m, *wt)))
- return;
+ if (k == "get" && ma.placeholder ())
+ {
+ error (ma.loc) << "(?) placeholder in the accessor expression"
+ << endl;
+ throw operation_failed ();
+ }
- // If it is none of the above then we have an error.
+ // Check that the member type is default-constructible if we
+ // have a placeholder in the modifier.
//
- 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;
-
- os << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " info: use '#pragma db type' to specify the database type"
- << endl;
+ if (k == "set" && ma.placeholder ())
+ {
+ // Assume all other types are default-constructible.
+ //
+ semantics::class_* c (dynamic_cast<semantics::class_*> (&t));
- throw operation_failed ();
+ if (c != 0 && !c->default_ctor ())
+ {
+ error (ma.loc) << "modifier expression requires member type "
+ << "to be default-constructible" << endl;
+ throw operation_failed ();
+ }
+ }
}
// Convert index/unique specifiers to the index entry in the object.
@@ -2480,9 +2710,7 @@ namespace relational
tt != CPP_EOF;
tt = lex_.next (t))
{
- cxx_token ct (lex_.location (), tt);
- ct.literal = t;
- i->cond.push_back (ct);
+ i->cond.push_back (cxx_token (lex_.location (), tt, t));
}
}
}
diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx
index a338b09..e525089 100644
--- a/odb/relational/source.cxx
+++ b/odb/relational/source.cxx
@@ -20,10 +20,13 @@ traverse_object (type& c)
data_member* id (id_member (c));
bool auto_id (id ? id->count ("auto") : false);
bool base_id (id ? &id->scope () != &c : false); // Comes from base.
+ member_access* id_ma (id ? &id->get<member_access> ("get") : 0);
bool has_ptr (has_a (c, test_pointer));
- data_member* optimistic (context::optimistic (c));
+ data_member* opt (optimistic (c));
+ member_access* opt_ma_get (opt ? &opt->get<member_access> ("get") : 0);
+ member_access* opt_ma_set (opt ? &opt->get<member_access> ("set") : 0);
type* poly_root (polymorphic (c));
bool poly (poly_root != 0);
@@ -42,7 +45,7 @@ traverse_object (type& c)
{
grow = context::grow (c);
grow_id = (id ? context::grow (*id) : false) ||
- (optimistic ? context::grow (*optimistic) : false);
+ (opt ? context::grow (*opt) : false);
}
string const& type (class_fq_name (c));
@@ -105,6 +108,8 @@ traverse_object (type& c)
//
if (!poly_derived && id != 0 && !base_id)
{
+ // id (image)
+ //
if (options.generate_query ())
{
os << traits << "::id_type" << endl
@@ -120,14 +125,16 @@ traverse_object (type& c)
<< "}";
}
- if (optimistic != 0)
+ // version (image)
+ //
+ if (opt != 0)
{
os << traits << "::version_type" << endl
<< traits << "::" << endl
<< "version (const image_type& i)"
<< "{"
<< "version_type v;";
- init_version_value_member_->traverse (*optimistic);
+ init_version_value_member_->traverse (*opt);
os << "return v;"
<< "}";
}
@@ -277,7 +284,7 @@ traverse_object (type& c)
{
os << "void " << traits << "::" << endl
<< "bind (" << bind_vector << " b, id_image_type& i" <<
- (optimistic != 0 ? ", bool bv" : "") << ")"
+ (opt != 0 ? ", bool bv" : "") << ")"
<< "{"
<< "std::size_t n (0);";
@@ -286,14 +293,14 @@ traverse_object (type& c)
bind_id_member_->traverse (*id);
- if (optimistic != 0)
+ if (opt != 0)
{
os << "if (bv)"
<< "{"
<< "n += " << column_count (c).id << ";"
<< endl;
- bind_version_member_->traverse (*optimistic);
+ bind_version_member_->traverse (*opt);
os << "}";
}
@@ -370,7 +377,7 @@ traverse_object (type& c)
{
os << "void " << traits << "::" << endl
<< "init (id_image_type& i, const id_type& id" <<
- (optimistic != 0 ? ", const version_type* v" : "") << ")"
+ (opt != 0 ? ", const version_type* v" : "") << ")"
<< "{";
if (grow_id)
@@ -381,13 +388,13 @@ traverse_object (type& c)
init_id_image_member_->traverse (*id);
- if (optimistic != 0)
+ if (opt != 0)
{
// Here we rely on the fact that init_image_member
// always wraps the statements in a block.
//
os << "if (v != 0)";
- init_version_image_member_->traverse (*optimistic);
+ init_version_image_member_->traverse (*opt);
}
if (grow_id)
@@ -625,8 +632,8 @@ traverse_object (type& c)
instance<object_columns> t (qtable, sk, sc);
t->traverse (*discriminator);
- if (optimistic != 0)
- t->traverse (*optimistic);
+ if (opt != 0)
+ t->traverse (*opt);
process_statement_columns (sc, statement_select);
}
@@ -696,10 +703,10 @@ traverse_object (type& c)
convert_to (qp->next (), i->type, *i->member));
}
- if (optimistic != 0 && !poly_derived)
+ if (opt != 0 && !poly_derived)
os << endl
- << strlit (" AND " + column_qname (*optimistic) + "=" +
- convert_to (qp->next (), *optimistic));
+ << strlit (" AND " + column_qname (*opt) + "=" +
+ convert_to (qp->next (), *opt));
os << ";"
<< endl;
}
@@ -725,7 +732,7 @@ traverse_object (type& c)
<< endl;
}
- if (optimistic != 0 && !poly_derived)
+ if (opt != 0 && !poly_derived)
{
instance<query_parameters> qp (table);
@@ -743,8 +750,8 @@ traverse_object (type& c)
}
os << endl
- << strlit (" AND " + column_qname (*optimistic) + "=" +
- convert_to (qp->next (), *optimistic)) << ";"
+ << strlit (" AND " + column_qname (*opt) + "=" +
+ convert_to (qp->next (), *opt)) << ";"
<< endl;
}
}
@@ -936,26 +943,66 @@ traverse_object (type& c)
if (!poly_derived && auto_id)
{
- if (const_type (id->type ()))
- os << "const_cast< id_type& > (obj." << id->name () << ")";
+ member_access& ma (id->get<member_access> ("set"));
+
+ if (ma.loc != 0)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ if (ma.placeholder ())
+ os << ma.translate ("obj", "static_cast< id_type > (st.id ())") << ";"
+ << endl;
else
- os << "obj." << id->name ();
+ {
+ // If this member is const and we have a synthesized access, then
+ // cast away constness. Otherwise, we assume that the user-provided
+ // expression handles this.
+ //
+ bool cast (ma.loc == 0 && const_type (id->type ()));
+ if (cast)
+ os << "const_cast< id_type& > (" << endl;
- os << " = static_cast< id_type > (st.id ());"
- << endl;
+ os << ma.translate ("obj");
+
+ if (cast)
+ os << ")";
+
+ os << " = static_cast< id_type > (st.id ());"
+ << endl;
+ }
}
- if (optimistic != 0 && !poly_derived)
+ // Set the optimistic concurrency version in the object member.
+ //
+ if (opt != 0 && !poly_derived)
{
- // Set the version in the object member.
+ // If we don't have auto id, then obj is a const reference.
//
- if (!auto_id || const_type (optimistic->type ()))
- os << "const_cast< version_type& > (obj." << optimistic->name () <<
- ") = 1;";
+ string obj (auto_id ? "obj" : "const_cast< object_type& > (obj)");
+
+ if (opt_ma_set->loc != 0)
+ os << "// From " << location_string (opt_ma_set->loc, true) << endl;
+
+ if (opt_ma_set->placeholder ())
+ os << opt_ma_set->translate (obj, "1") << ";"
+ << endl;
else
- os << "obj." << optimistic->name () << " = 1;";
+ {
+ // If this member is const and we have a synthesized access, then
+ // cast away constness. Otherwise, we assume that the user-provided
+ // expression handles this.
+ //
+ bool cast (opt_ma_set->loc == 0 && const_type (opt->type ()));
+ if (cast)
+ os << "const_cast< version_type& > (" << endl;
- os << endl;
+ os << opt_ma_set->translate (obj);
+
+ if (cast)
+ os << ")";
+
+ os << " = 1;"
+ << endl;
+ }
}
// Initialize id_image and binding if we are a root of a polymorphic
@@ -971,8 +1018,12 @@ traverse_object (type& c)
os << "if (!top)"
<< "{";
- os << "id_image_type& i (sts.id_image ());"
- << "init (i, obj." << id->name () << ");"
+ os << "id_image_type& i (sts.id_image ());";
+
+ if (id_ma->loc != 0)
+ os << "// From " << location_string (id_ma->loc, true) << endl;
+
+ os << "init (i, " << id_ma->translate ("obj") << ");"
<< endl
<< "binding& idb (sts.id_image_binding ());"
<< "if (i.version != sts.id_image_version () || idb.version == 0)"
@@ -1100,8 +1151,12 @@ traverse_object (type& c)
os << "if (!top)";
os << "{"
- << "id_image_type& i (sts.id_image ());"
- << "init (i, obj." << id->name () << ");"
+ << "id_image_type& i (sts.id_image ());";
+
+ if (id_ma->loc != 0)
+ os << "// From " << location_string (id_ma->loc, true) << endl;
+
+ os << "init (i, " << id_ma->translate ("obj") << ");"
<< endl;
os << "binding& idb (sts.id_image_binding ());"
@@ -1161,9 +1216,11 @@ traverse_object (type& c)
// exists in the database. Use the discriminator_() call for
// that.
//
- os << "root_traits::discriminator_ (sts.root_statements (), obj." <<
- id->name () << ", 0);"
- << endl;
+ if (id_ma->loc != 0)
+ os << "// From " << location_string (id_ma->loc, true) << endl;
+
+ os << "root_traits::discriminator_ (sts.root_statements (), " <<
+ id_ma->translate ("obj") << ", 0);" << endl;
}
// Otherwise, nothing else to do here if we don't have any columns
// to update.
@@ -1179,15 +1236,27 @@ traverse_object (type& c)
// Initialize object and id images.
//
+ if (opt != 0)
+ {
+ if (opt_ma_get->loc != 0)
+ os << "// From " << location_string (opt_ma_get->loc, true) << endl;
+
+ os << "const version_type& v (" << endl
+ << opt_ma_get->translate ("obj") << ");";
+ }
+
os << "id_image_type& i (sts.id_image ());";
- if (optimistic == 0)
- os << "init (i, obj." << id->name () << ");";
- else
- os << "init (i, obj." << id->name () << ", &obj." <<
- optimistic->name () << ");";
+ if (id_ma->loc != 0)
+ os << "// From " << location_string (id_ma->loc, true) << endl;
- os << endl
+ os << "init (i, " << id_ma->translate ("obj");
+
+ if (opt != 0)
+ os << ", &v";
+
+ os << ");"
+ << endl
<< "image_type& im (sts.image ());";
if (generate_grow)
@@ -1245,7 +1314,7 @@ traverse_object (type& c)
os << "if (sts.update_statement ().execute () == 0)" << endl;
- if (optimistic == 0)
+ if (opt == 0)
os << "throw object_not_persistent ();";
else
os << "throw object_changed ();";
@@ -1265,21 +1334,29 @@ traverse_object (type& c)
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl;
+ if (id_ma->loc != 0)
+ os << "// From " << location_string (id_ma->loc, true) << endl;
+
+ os << "const id_type& id (" << endl
+ << id_ma->translate ("obj") << ");"
+ << endl;
+
if (poly)
{
// In case of a polymorphic root, use discriminator_(), which
// is faster. And initialize the id image, unless this is a
// top-level call.
//
- os << "discriminator_ (sts, obj." << id->name () << ", 0);"
+ os << "discriminator_ (sts, id, 0);"
<< endl;
if (!abst)
os << "if (!top)";
os << "{"
- << "id_image_type& i (sts.id_image ());"
- << "init (i, obj." << id->name () << ");"
+ << "id_image_type& i (sts.id_image ());";
+
+ os << "init (i, id);"
<< endl;
os << "binding& idb (sts.id_image_binding ());"
@@ -1293,7 +1370,7 @@ traverse_object (type& c)
}
else
{
- os << "if (!find_ (sts, &obj." << id->name () << "))" << endl
+ os << "if (!find_ (sts, &id))" << endl
<< "throw object_not_persistent ();"
<< endl;
@@ -1312,11 +1389,46 @@ traverse_object (type& c)
t->traverse (c);
}
- if (optimistic != 0 && !poly_derived)
+ // Update the optimistic concurrency version in the object member.
+ //
+ if (opt != 0 && !poly_derived)
{
- // Update version in the object member.
+ // Object is passed as const reference so we need to cast away
+ // constness.
//
- os << "const_cast<version_type&> (obj." << optimistic->name () << ")++;";
+ string obj ("const_cast< object_type& > (obj)");
+
+ if (opt_ma_set->loc != 0)
+ os << "// From " << location_string (opt_ma_set->loc, true) << endl;
+
+ if (opt_ma_set->placeholder ())
+ {
+ if (opt_ma_get->loc != 0)
+ os << "// From " << location_string (opt_ma_get->loc, true) <<
+ endl;
+
+ os << opt_ma_set->translate (
+ obj, opt_ma_get->translate ("obj") + " + 1") << ";"
+ << endl;
+ }
+ else
+ {
+ // If this member is const and we have a synthesized access, then
+ // cast away constness. Otherwise, we assume that the user-provided
+ // expression handles this.
+ //
+ bool cast (opt_ma_set->loc == 0 && const_type (opt->type ()));
+ if (cast)
+ os << "const_cast< version_type& > (" << endl;
+
+ os << opt_ma_set->translate (obj);
+
+ if (cast)
+ os << ")";
+
+ os << "++;"
+ << endl;
+ }
}
// Call callback (post_update).
@@ -1457,7 +1569,7 @@ traverse_object (type& c)
// erase (object)
//
- if (id != 0 && (poly || optimistic != 0))
+ if (id != 0 && (poly || opt != 0))
{
os << "void " << traits << "::" << endl
<< "erase (database& db, const object_type& obj";
@@ -1497,7 +1609,7 @@ traverse_object (type& c)
// Determine the dynamic type of this object.
//
- if (optimistic == 0)
+ if (opt == 0)
{
os << "callback (db, obj, callback_event::pre_erase);"
<< "erase (db, id (obj), true, false);"
@@ -1530,6 +1642,16 @@ traverse_object (type& c)
<< endl;
}
+ if (!abst || straight_containers)
+ {
+ if (id_ma->loc != 0)
+ os << "// From " << location_string (id_ma->loc, true) << endl;
+
+ os << "const id_type& id (" << endl
+ << id_ma->translate ("obj") << ");"
+ << endl;
+ }
+
// Initialize id + managed column image.
//
os << "binding& idb (" << rsts << ".id_image_binding ());"
@@ -1541,9 +1663,13 @@ traverse_object (type& c)
os << "if (top)"
<< "{";
- os << "id_image_type& i (" << rsts << ".id_image ());"
- << "init (i, obj." << id->name () << ", &obj." <<
- optimistic->name () << ");"
+ if (opt_ma_get->loc != 0)
+ os << "// From " << location_string (opt_ma_get->loc, true) << endl;
+
+ os << "const version_type& v (" << endl
+ << opt_ma_get->translate ("obj") << ");"
+ << "id_image_type& i (" << rsts << ".id_image ());"
+ << "init (i, id, &v);"
<< endl;
// To update the id part of the optimistic id binding we have
@@ -1592,10 +1718,13 @@ traverse_object (type& c)
os << "if (top)"
<< "{"
<< "version_type v;"
- << "root_traits::discriminator_ (" << rsts << ", obj." <<
- id->name () << ", 0, &v);"
- << endl
- << "if (v != obj." << optimistic->name () << ")" << endl
+ << "root_traits::discriminator_ (" << rsts << ", id, 0, &v);"
+ << endl;
+
+ if (opt_ma_get->loc != 0)
+ os << "// From " << location_string (opt_ma_get->loc, true) << endl;
+
+ os << "if (v != " << opt_ma_get->translate ("obj") << ")" << endl
<< "throw object_changed ();"
<< "}";
}
@@ -1618,15 +1747,19 @@ traverse_object (type& c)
// have been more efficient but it would complicated and bloat
// things significantly.
//
- os << "if (!find_ (sts, &obj." << id->name () << "))" << endl
+ os << "if (!find_ (sts, &id))" << endl
<< "throw object_changed ();"
<< endl;
if (delay_freeing_statement_result)
- os << "sts.find_statement ().free_result ();";
+ os << "sts.find_statement ().free_result ();"
+ << endl;
+
+ if (opt_ma_get->loc != 0)
+ os << "// From " << location_string (opt_ma_get->loc, true) << endl;
- os << "if (version (sts.image ()) != obj." <<
- optimistic->name () << ")" << endl
+ os << "if (version (sts.image ()) != " <<
+ opt_ma_get->translate ("obj") << ")" << endl
<< "throw object_changed ();"
<< endl;
}
@@ -1666,7 +1799,7 @@ traverse_object (type& c)
// Remove from the object cache.
//
- os << "pointer_cache_traits::erase (db, obj." << id->name () << ");";
+ os << "pointer_cache_traits::erase (db, id);";
// Call callback (post_erase).
//
@@ -2015,7 +2148,14 @@ traverse_object (type& c)
<< "statements_type::auto_lock l (" << rsts << ");"
<< endl;
- os << "if (!find_ (sts, &obj." << id->name () << "))" << endl
+ if (id_ma->loc != 0)
+ os << "// From " << location_string (id_ma->loc, true) << endl;
+
+ os << "const id_type& id (" << endl
+ << id_ma->translate ("obj") << ");"
+ << endl;
+
+ os << "if (!find_ (sts, &id))" << endl
<< "return false;"
<< endl;
@@ -2028,10 +2168,14 @@ traverse_object (type& c)
os << "auto_result ar (st);"
<< endl;
- if (optimistic != 0)
+ if (opt != 0)
{
+ if (opt_ma_get->loc != 0)
+ os << "// From " << location_string (opt_ma_get->loc, true) << endl;
+
os << "if (" << (poly_derived ? "root_traits::" : "") << "version (" <<
- rsts << ".image ()) == obj." << optimistic->name () << ")" << endl
+ rsts << ".image ()) == " << opt_ma_get->translate ("obj") <<
+ ")" << endl
<< "return true;"
<< endl;
}
@@ -2272,7 +2416,7 @@ traverse_object (type& c)
<< "const id_type& id," << endl
<< "discriminator_type* pd";
- if (optimistic != 0)
+ if (opt != 0)
os << "," << endl
<< "version_type* pv";
@@ -2291,7 +2435,7 @@ traverse_object (type& c)
<< "if (idi.version != sts.discriminator_id_image_version () ||" << endl
<< "idb.version == 0)"
<< "{"
- << "bind (idb.bind, idi" << (optimistic != 0 ? ", false" : "") << ");"
+ << "bind (idb.bind, idi" << (opt != 0 ? ", false" : "") << ");"
<< "sts.discriminator_id_image_version (idi.version);"
<< "idb.version++;"
<< "}";
@@ -2313,11 +2457,11 @@ traverse_object (type& c)
bind_discriminator_member_->traverse (*discriminator);
os << "}";
- if (optimistic != 0)
+ if (opt != 0)
{
os << "n++;" // For now discriminator is a simple value.
<< "{";
- bind_version_member_->traverse (*optimistic);
+ bind_version_member_->traverse (*opt);
os << "}";
}
@@ -2334,7 +2478,7 @@ traverse_object (type& c)
<< "if (r == select_statement::no_data)"
<< "{";
- if (optimistic != 0)
+ if (opt != 0)
os << "if (pv != 0)" << endl
<< "throw object_changed ();"
<< "else" << endl;
@@ -2342,9 +2486,9 @@ traverse_object (type& c)
os << "throw object_not_persistent ();"
<< "}";
- if (generate_grow && (
- context::grow (*discriminator) ||
- (optimistic != 0 && context::grow (*optimistic))))
+ if (generate_grow &&
+ (context::grow (*discriminator) ||
+ (opt != 0 && context::grow (*opt))))
{
os << "else if (r == select_statement::truncated)"
<< "{";
@@ -2358,8 +2502,8 @@ traverse_object (type& c)
index_ = 0;
grow_discriminator_member_->traverse (*discriminator);
- if (optimistic != 0)
- grow_version_member_->traverse (*optimistic);
+ if (opt != 0)
+ grow_version_member_->traverse (*opt);
os << "if (grew)" << endl
<< "i.version++;"
@@ -2375,11 +2519,11 @@ traverse_object (type& c)
bind_discriminator_member_->traverse (*discriminator);
os << "}";
- if (optimistic != 0)
+ if (opt != 0)
{
os << "n++;" // For now discriminator is a simple value.
<< "{";
- bind_version_member_->traverse (*optimistic);
+ bind_version_member_->traverse (*opt);
os << "}";
}
@@ -2404,12 +2548,12 @@ traverse_object (type& c)
init_named_discriminator_value_member_->traverse (*discriminator);
os << "}";
- if (optimistic != 0)
+ if (opt != 0)
{
os << "if (pv != 0)"
<< "{"
<< "version_type& v (*pv);";
- init_named_version_value_member_->traverse (*optimistic);
+ init_named_version_value_member_->traverse (*opt);
os << "}";
}
@@ -2618,10 +2762,7 @@ traverse_view (type& c)
else
// Output the pragma location for easier error tracking.
//
- os << "// From " <<
- location_file (vq.loc).leaf () << ":" <<
- location_line (vq.loc) << ":" <<
- location_column (vq.loc) << endl
+ os << "// From " << location_string (vq.loc, true) << endl
<< translate_expression (
c, vq.expr, vq.scope, vq.loc, "query", &ph).value;
@@ -2707,13 +2848,10 @@ traverse_view (type& c)
l += " ON";
+ // Output the pragma location for easier error tracking.
+ //
os << "r += " << strlit (l) << ";"
- // Output the pragma location for easier error tracking.
- //
- << "// From " <<
- location_file (i->loc).leaf () << ":" <<
- location_line (i->loc) << ":" <<
- location_column (i->loc) << endl
+ << "// From " << location_string (i->loc, true) << endl
<< "r += " << e.value << ";"
<< endl;
@@ -2775,13 +2913,10 @@ traverse_view (type& c)
l += " ON";
+ // Output the pragma location for easier error tracking.
+ //
os << "r += " << strlit (l) << ";"
- // Output the pragma location for easier error tracking.
- //
- << "// From " <<
- location_file (i->loc).leaf () << ":" <<
- location_line (i->loc) << ":" <<
- location_column (i->loc) << endl
+ << "// From " << location_string (i->loc, true) << endl
<< "r += " << e.value << ";";
if (poly_depth != 1)
@@ -3210,10 +3345,7 @@ traverse_view (type& c)
{
// Output the pragma location for easier error tracking.
//
- os << "// From " <<
- location_file (vq.loc).leaf () << ":" <<
- location_line (vq.loc) << ":" <<
- location_column (vq.loc) << endl
+ os << "// From " << location_string (vq.loc, true) << endl
<< translate_expression (
c, vq.expr, vq.scope, vq.loc, "query", &ph).value;
@@ -3596,6 +3728,9 @@ namespace relational
string const& prag,
bool* placeholder)
{
+ // This code is similar to translate() from context.cxx.
+ //
+
// The overall idea is as folows: read in tokens and add them
// to the string. If a token starts a name, try to resolve it
// to an object member (taking into account aliases). If this
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index a1f1190..38bb80f 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -1127,6 +1127,9 @@ namespace relational
virtual void
set_null (member_info&) = 0;
+ virtual void
+ check_accessor (member_info&, member_access&) {}
+
virtual bool
pre (member_info& mi)
{
@@ -1142,8 +1145,13 @@ namespace relational
if (mi.ptr != 0 && mi.m.count ("polymorphic-ref"))
return false;
+ bool comp (composite (mi.t));
+
if (!member_override_.empty ())
+ {
member = member_override_;
+ os << "{";
+ }
else
{
// If we are generating standard init() and this member
@@ -1158,9 +1166,7 @@ namespace relational
if (!insert_send_auto_id && id (mi.m) && auto_ (mi.m))
return false;
- string const& name (mi.m.name ());
-
- os << "// " << name << endl
+ os << "// " << mi.m.name () << endl
<< "//" << endl;
// If the whole class is readonly, then we will never be
@@ -1176,13 +1182,37 @@ namespace relational
os << "if (sk == statement_insert)";
}
+ os << "{";
+
if (discriminator (mi.m))
member = "di.discriminator";
else
- member = "o." + name;
- }
+ {
+ // Get the member using the accessor expression.
+ //
+ member_access& ma (mi.m.template get<member_access> ("get"));
- bool comp (composite (mi.t));
+ // Make sure this kind of member can be accessed with this
+ // kind of accessor (database-specific, e.g., streaming).
+ //
+ if (!comp)
+ check_accessor (mi, ma);
+
+ // If this is not a synthesized expression, then output
+ // its location for easier error tracking.
+ //
+ if (ma.loc != 0)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ // Use the original type to form the const reference.
+ //
+ os << member_ref_type (mi.m, true, "v") << " (" << endl
+ << ma.translate ("o") << ");"
+ << endl;
+
+ member = "v";
+ }
+ }
// If this is a wrapped composite value, then we need to "unwrap"
// it. If this is a NULL wrapper, then we also need to handle that.
@@ -1205,14 +1235,13 @@ namespace relational
member << "))" << endl
<< "composite_value_traits< " + mi.fq_type () + " >::" <<
"set_null (i." << mi.var << "value, sk);"
- << "else";
+ << "else"
+ << "{";
}
member = "wrapper_traits< " + wt + " >::get_ref (" + member + ")";
}
- os << "{";
-
if (discriminator (mi.m))
os << "const info_type& di (map->find (typeid (o)));"
<< endl;
@@ -1301,6 +1330,13 @@ namespace relational
set_null (mi);
}
+ if (mi.wrapper != 0 && composite (mi.t))
+ {
+ if (null (mi.m, key_prefix_) &&
+ mi.wrapper->template get<bool> ("wrapper-null-handler"))
+ os << "}";
+ }
+
os << "}";
}
@@ -1430,6 +1466,9 @@ namespace relational
virtual void
get_null (member_info&) = 0;
+ virtual void
+ check_modifier (member_info&, member_access&) {}
+
virtual bool
pre (member_info& mi)
{
@@ -1447,25 +1486,66 @@ namespace relational
if (ignore_implicit_discriminator_ && discriminator (mi.m))
return false;
+ bool comp (composite (mi.t));
+
if (!member_override_.empty ())
+ {
+ os << "{";
member = member_override_;
+ }
else
{
- string const& name (mi.m.name ());
- member = "o." + name;
+ os << "// " << mi.m.name () << endl
+ << "//" << endl
+ << "{";
+
+ // Get the member using the accessor expression.
+ //
+ member_access& ma (mi.m.template get<member_access> ("set"));
+
+ // Make sure this kind of member can be modified with this
+ // kind of accessor (database-specific, e.g., streaming).
+ //
+ if (!comp)
+ check_modifier (mi, ma);
- if (mi.cq)
+ // If this is not a synthesized expression, then output
+ // its location for easier error tracking.
+ //
+ if (ma.loc != 0)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ // See if we are modifying via a reference or proper modifier.
+ //
+ if (ma.placeholder ())
+ os << member_val_type (mi.m, false, "v") << ";"
+ << endl;
+ else
{
- string t (mi.ptr == 0 ? mi.fq_type (false) : mi.ptr_fq_type ());
- member = "const_cast< " + t + "& > (" + member + ")";
+ // Use the original type to form the reference.
+ //
+ os << member_ref_type (mi.m, false, "v") << " (" << endl;
+
+ // If this member is const and we have a synthesized access,
+ // then cast away constness. Otherwise, we assume that the
+ // user-provided expression handles this.
+ //
+ if (mi.cq && ma.loc == 0)
+ os << "const_cast< " << member_ref_type (mi.m, false) <<
+ " > (" << endl;
+
+ os << ma.translate ("o");
+
+ if (mi.cq && ma.loc == 0)
+ os << ")";
+
+ os << ");"
+ << endl;
}
- os << "// " << name << endl
- << "//" << endl;
+ member = "v";
}
- bool comp (composite (mi.t));
-
// If this is a wrapped composite value, then we need to "unwrap" it.
// If this is a NULL wrapper, then we also need to handle that. For
// simple values this is taken care of by the value_traits
@@ -1498,8 +1578,7 @@ namespace relational
// Handle NULL pointers and extract the id.
//
- os << "{"
- << "typedef object_traits< " << class_fq_name (*mi.ptr) <<
+ os << "typedef object_traits< " << class_fq_name (*mi.ptr) <<
" > obj_traits;"
<< "typedef odb::pointer_traits< " << mi.ptr_fq_type () <<
" > ptr_traits;"
@@ -1548,16 +1627,9 @@ namespace relational
{
if (mi.ptr != 0)
{
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- member = "o." + mi.m.name ();
-
- if (mi.cq)
- member = "const_cast< " + mi.ptr_fq_type () +
- "& > (" + member + ")";
- }
+ // Restore the member variable name.
+ //
+ member = member_override_.empty () ? "v" : member_override_;
// When handling a pointer, mi.t is the id type of the referenced
// object.
@@ -1592,9 +1664,28 @@ namespace relational
}
}
- os << "}"
- << "}";
+ os << "}";
+ }
+
+ // Call the modifier if we are using a proper one.
+ //
+ if (member_override_.empty ())
+ {
+ member_access& ma (mi.m.template get<member_access> ("set"));
+
+ if (ma.placeholder ())
+ {
+ // If this is not a synthesized expression, then output its
+ // location for easier error tracking.
+ //
+ if (ma.loc != 0)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ os << ma.translate ("o", "v") << ";";
+ }
}
+
+ os << "}";
}
virtual void
@@ -2867,9 +2958,10 @@ namespace relational
};
container_calls (call_type call)
- : object_members_base (true, false, false),
+ : object_members_base (true, false, true),
call_ (call),
- obj_prefix_ ("obj.")
+ obj_prefix_ ("obj"),
+ modifier_ (0)
{
}
@@ -2878,17 +2970,56 @@ namespace relational
semantics::class_& c,
semantics::type* w)
{
- if (m == 0)
+ if (m == 0 || call_ == erase_call || modifier_ != 0)
{
object_members_base::traverse_composite (m, c);
return;
}
- string old (obj_prefix_);
- obj_prefix_ += m->name ();
+ // Get this member using the accessor expression.
+ //
+ member_access& ma (
+ m->get<member_access> (call_ == load_call ? "set" : "get"));
+
+ // We don't support by-value modifiers for composite values
+ // with containers. However, at this point we don't know
+ // whether this composite value has any containers. So we
+ // are just going to set a flag that can be checked in
+ // traverse_container() below.
+ //
+ if (ma.placeholder ())
+ {
+ modifier_ = &ma;
+ object_members_base::traverse_composite (m, c);
+ modifier_ = 0;
+ return;
+ }
+
+ string old_op (obj_prefix_);
+ string old_f (from_);
+ obj_prefix_.clear ();
- // If this is a wrapped composite value, then we need to
- // "unwrap" it.
+ // If this member is const and we have a synthesized access,
+ // then cast away constness. Otherwise, we assume that the
+ // user-provided expression handles this.
+ //
+ if (call_ == load_call && ma.loc == 0 && const_type (m->type ()))
+ obj_prefix_ = "const_cast< " + member_ref_type (*m, false) +
+ " > (\n";
+
+ obj_prefix_ += ma.translate (old_op);
+
+ if (call_ == load_call && ma.loc == 0 && const_type (m->type ()))
+ obj_prefix_ += ")";
+
+ // If this is not a synthesized expression, then store its
+ // location which we will output later for easier error
+ // tracking.
+ //
+ if (ma.loc != 0)
+ from_ += "// From " + location_string (ma.loc, true) + "\n";
+
+ // If this is a wrapped composite value, then we need to "unwrap" it.
//
if (w != 0)
{
@@ -2900,26 +3031,14 @@ namespace relational
//
assert (&t == w);
- string const& type (t.fq_name (hint));
-
- if (call_ == load_call && const_type (m->type ()))
- obj_prefix_ = "const_cast< " + type + "& > (\n" +
- obj_prefix_ + ")";
-
- obj_prefix_ = "wrapper_traits< " + type + " >::" +
+ obj_prefix_ = "wrapper_traits< " + t.fq_name (hint) + " >::" +
(call_ == load_call ? "set_ref" : "get_ref") +
" (\n" + obj_prefix_ + ")";
}
- else if (call_ == load_call && const_type (m->type ()))
- {
- obj_prefix_ = "const_cast< " + class_fq_name (c) + "& > (\n" +
- obj_prefix_ + ")";
- }
-
- obj_prefix_ += '.';
object_members_base::traverse_composite (m, c);
- obj_prefix_ = old;
+ from_ = old_f;
+ obj_prefix_ = old_op;
}
virtual void
@@ -2929,87 +3048,155 @@ namespace relational
bool inverse (context::inverse (m, "value"));
+ // In certain cases we don't need to do anything.
+ //
+ if ((call_ != load_call && inverse) ||
+ (call_ == update_call && readonly (member_path_, member_scope_)))
+ return;
+
string const& name (m.name ());
- string obj_name (obj_prefix_ + name);
string sts_name (flat_prefix_ + name);
string traits (flat_prefix_ + public_name (m) + "_traits");
- if (call_ == load_call && const_type (m.type ()))
- {
-
- }
+ os << "// " << member_prefix_ << m.name () << endl
+ << "//" << endl;
- semantics::names* hint;
- semantics::type& t (utype (m, hint));
+ // Get this member using the accessor expression.
+ //
+ string var;
+ member_access& ma (
+ m.get<member_access> (call_ == load_call ? "set" : "get"));
- // If this is a wrapped container, then we need to "unwrap" it.
+ // We don't support by-value modifiers for composite values
+ // with containers.
//
- if (wrapper (t))
+ if (call_ == load_call && modifier_ != 0)
+ {
+ error (modifier_->loc) << "by-value modification of a composite "
+ << "value with container is not supported"
+ << endl;
+ info (m.location ()) << "container member is defined here" << endl;
+ throw operation_failed ();
+ }
+
+ if (call_ != erase_call)
{
- string const& type (t.fq_name (hint));
+ os << "{";
- // We cannot use traits::container_type here.
+ // Output stored locations, if any.
//
- if (call_ == load_call && const_type (m.type ()))
- obj_name = "const_cast< " + type + "& > (\n" + obj_name + ")";
+ if (!ma.placeholder ())
+ os << from_;
- obj_name = "wrapper_traits< " + type + " >::" +
- (call_ == load_call ? "set_ref" : "get_ref") +
- " (\n" + obj_name + ")";
- }
- else if (call_ == load_call && const_type (m.type ()))
- {
- obj_name = "const_cast< " + traits + "::container_type& > (\n" +
- obj_name + ")";
- }
+ // If this is not a synthesized expression, then output its
+ // location for easier error tracking.
+ //
+ if (ma.loc != 0)
+ os << "// From " << location_string (ma.loc, true) << endl;
+ // See if we are modifying via a reference or proper modifier.
+ //
+ if (ma.placeholder ())
+ os << member_val_type (m, false, "v") << ";"
+ << endl;
+ else
+ {
+ os << member_ref_type (m, call_ != load_call, "v") << " (" << endl;
+
+ // If this member is const and we have a synthesized access,
+ // then cast away constness. Otherwise, we assume that the
+ // user-provided expression handles this.
+ //
+ if (call_ == load_call && ma.loc == 0 && const_type (m.type ()))
+ os << "const_cast< " << member_ref_type (m, false) <<
+ " > (" << endl;
+
+ os << ma.translate (obj_prefix_);
+
+ if (call_ == load_call && ma.loc == 0 && const_type (m.type ()))
+ os << ")";
+
+ os << ");"
+ << endl;
+ }
+
+ var = "v";
+
+ semantics::names* hint;
+ semantics::type& t (utype (m, hint));
+
+ // If this is a wrapped container, then we need to "unwrap" it.
+ //
+ if (wrapper (t))
+ {
+ var = "wrapper_traits< " + t.fq_name (hint) + " >::" +
+ (call_ == load_call ? "set_ref" : "get_ref") + " (" + var + ")";
+ }
+ }
switch (call_)
{
case persist_call:
{
- if (!inverse)
- os << traits << "::persist (" << endl
- << obj_name << "," << endl
- << "idb," << endl
- << "sts.container_statment_cache ()." << sts_name << ");"
- << endl;
+ os << traits << "::persist (" << endl
+ << var << "," << endl
+ << "idb," << endl
+ << "sts.container_statment_cache ()." << sts_name << ");";
break;
}
case load_call:
{
os << traits << "::load (" << endl
- << obj_name << "," << endl
+ << var << "," << endl
<< "idb," << endl
- << "sts.container_statment_cache ()." << sts_name << ");"
- << endl;
+ << "sts.container_statment_cache ()." << sts_name << ");";
break;
}
case update_call:
{
- if (!(inverse || readonly (member_path_, member_scope_)))
- os << traits << "::update (" << endl
- << obj_name << "," << endl
- << "idb," << endl
- << "sts.container_statment_cache ()." << sts_name << ");"
- << endl;
+ os << traits << "::update (" << endl
+ << var << "," << endl
+ << "idb," << endl
+ << "sts.container_statment_cache ()." << sts_name << ");";
break;
}
case erase_call:
{
- if (!inverse)
- os << traits << "::erase (" << endl
- << "idb," << endl
- << "sts.container_statment_cache ()." << sts_name << ");"
- << endl;
+ os << traits << "::erase (" << endl
+ << "idb," << endl
+ << "sts.container_statment_cache ()." << sts_name << ");"
+ << endl;
break;
}
}
+
+ if (call_ != erase_call)
+ {
+ // Call the modifier if we are using a proper one.
+ //
+ if (ma.placeholder ())
+ {
+ os << endl
+ << from_;
+
+ // If this is not a synthesized expression, then output its
+ // location for easier error tracking.
+ //
+ if (ma.loc != 0)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ os << ma.translate (obj_prefix_, "v") << ";";
+ }
+
+ os << "}";
+ }
}
protected:
call_type call_;
string obj_prefix_;
+ string from_;
+ member_access* modifier_;
};
// Output a list of parameters for the persist statement.