From d001ec3018787138c2db6c5f6949a00807582774 Mon Sep 17 00:00:00 2001
From: Boris Kolpackov
Date: Wed, 21 Sep 2011 13:00:34 +0200
Subject: Rework const object handling
Now objects are always loaded as non-const and the object cache in
session treats all objects as non-const.
---
NEWS | 5 +++
doc/manual.xhtml | 59 +++++++++++++++++++--------------
odb/relational/header.hxx | 11 +------
odb/relational/mysql/source.cxx | 2 +-
odb/relational/pgsql/source.cxx | 2 +-
odb/relational/source.hxx | 70 ++++++++--------------------------------
odb/relational/sqlite/source.cxx | 2 +-
7 files changed, 56 insertions(+), 95 deletions(-)
diff --git a/NEWS b/NEWS
index d997127..0effbe2 100644
--- a/NEWS
+++ b/NEWS
@@ -70,6 +70,11 @@ Version 1.6.0
For more information, refer to Section 11.2, "MySQL Database Class" in
the ODB manual.
+ * Object cache maintained by a session nor longer distinguishes between
+ const and non-const objects. Instead, const objects are treated as
+ non-const by casting away constness. For more information on this new
+ behavior, refer to Section 9.1, "Object Cache" in the ODB manual.
+
Version 1.5.0
* Support for the PostgreSQL database. The provided connection factories
diff --git a/doc/manual.xhtml b/doc/manual.xhtml
index 13c694f..7e68f6f 100644
--- a/doc/manual.xhtml
+++ b/doc/manual.xhtml
@@ -3060,12 +3060,6 @@ namespace odb
what () const throw ();
};
- struct const_object: exception
- {
- virtual const char*
- what () const throw ();
- };
-
// Database operations exceptions.
//
struct recoverable: exception
@@ -3137,11 +3131,9 @@ namespace odb
odb::transaction
class and are discussed
in Section 3.4, "Transactions".
- The next three exceptions (already_in_session
,
- not_in_session
, and
- const_object
) are thrown by the
- odb::session
class and are discussed
- in Chapter 9, "Session".
+ The next two exceptions (already_in_session
, and
+ not_in_session
) are thrown by the odb::session
+ class and are discussed in Chapter 9, "Session".
The recoverable
exception serves as a common base
for all the recoverable exceptions, which are: connection_lost
,
@@ -6051,26 +6043,43 @@ t.commit ();
a pre-allocated instance, the object is only cached if its object
pointer is a raw pointer.
- Finally, the session caches both constant and unrestricted objects,
- depending on whether a constant reference or constant pointer was
- passed to the database::persist()
function (in contrast,
- when loaded, objects are always created and cached as unrestricted).
- If we try to load an object as unrestricted that was previously
- persisted and cached as constant, the odb::const_object
- exception is thrown. The following transaction shows the
- situation where this would happen:
+ Also note that when we persist an object as a constant reference
+ or constant pointer, the session caches such an object as
+ unrestricted (non-const
). This can lead to undefined
+ behavior if the object being persisted was actually created as
+ const
and is later found in the session cache and
+ used as non-const
. As a result, when using sessions,
+ it is recommended that all persistent objects are created as
+ non-const
instances. The following code fragment
+ illustrates this point:
-shared_ptr<const person> p (new person ("John", "Doe"));
+void save (database& db, shared_ptr<const person> p)
+{
+ transaction t (db.begin ());
+ db.persist (p); // Persisted as const pointer.
+ t.commit ();
+}
session s;
-transaction t (db.begin ());
-unsigned long id (db.persist (p));
-shared_ptr<const person> p1 (db.load<const person> (id)); // Ok.
-shared_ptr<person> p2 (db.load<person> (id)); // Exception.
+shared_ptr<const person> p1 (new const person ("John", "Doe"));
+unsigned long id1 (save (db, p1)); // p1 is cached in s as non-const.
-t.commit ();
+{
+ transaction t (db.begin ());
+ shared_ptr<person> p (db.load<person> (id1)); // p == p1
+ p->age (30); // Undefined behavior since p1 was created const.
+}
+
+shared_ptr<const person> p2 (new person ("Jane", "Doe"));
+unsigned long id2 (save (db, p2)); // p2 is cached in s as non-const.
+
+{
+ transaction t (db.begin ());
+ shared_ptr<person> p (db.load<person> (id2)); // p == p2
+ p->age (30); // Ok, since p2 was not created const.
+}
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index e4933a0..50a40b2 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -1163,8 +1163,7 @@ namespace relational
//
if (options.generate_query ())
{
- os << "template" << endl
- << "static result" << endl
+ os << "static result" << endl
<< "query (database&, const query_base_type&);"
<< endl;
@@ -1204,14 +1203,6 @@ namespace relational
"object_type&);"
<< endl;
- if (options.generate_query ())
- os << "static void" << endl
- << "query_ (database&," << endl
- << "const query_base_type&," << endl
- << db << "::object_statements< object_type >&," << endl
- << "details::shared_ptr< " << db << "::select_statement >&);"
- << endl;
-
os << "};";
}
diff --git a/odb/relational/mysql/source.cxx b/odb/relational/mysql/source.cxx
index 8f80a5a..bea559e 100644
--- a/odb/relational/mysql/source.cxx
+++ b/odb/relational/mysql/source.cxx
@@ -885,7 +885,7 @@ namespace relational
<< "// cannot be initialized from an object pointer." << endl
<< "//" << endl
<< member << " = ptr_traits::pointer_type (" << endl
- << "db.load< ptr_traits::element_type > (id));";
+ << "db.load< obj_traits::object_type > (id));";
os << "}"
<< "}";
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
index 6c4a656..5b77e41 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/relational/pgsql/source.cxx
@@ -761,7 +761,7 @@ namespace relational
<< "// cannot be initialized from an object pointer." << endl
<< "//" << endl
<< member << " = ptr_traits::pointer_type (" << endl
- << "db.load< ptr_traits::element_type > (id));";
+ << "db.load< obj_traits::object_type > (id));";
os << "}"
<< "}";
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index 92a406b..3474f15 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -2706,12 +2706,9 @@ namespace relational
{
// query ()
//
- os << "template<>" << endl
- << "result< " << traits << "::object_type >" << endl
+ os << "result< " << traits << "::object_type >" << endl
<< traits << "::" << endl
- << "query< " << traits << "::object_type > (" << endl
- << "database& db," << endl
- << "const query_base_type& q)"
+ << "query (database&, const query_base_type& q)"
<< "{"
<< "using namespace " << db << ";"
<< "using odb::details::shared;"
@@ -2722,55 +2719,6 @@ namespace relational
<< endl
<< "object_statements< object_type >& sts (" << endl
<< "conn.statement_cache ().find_object ());"
- << "shared_ptr st;"
- << endl
- << "query_ (db, q, sts, st);"
- << endl
- << "shared_ptr > r (" << endl
- << "new (shared) " << db <<
- "::result_impl (" << endl
- << "q, st, sts));"
- << endl
- << "return result (r);"
- << "}";
-
- os << "template<>" << endl
- << "result< const " << traits << "::object_type >" << endl
- << traits << "::" << endl
- << "query< const " << traits << "::object_type > (" << endl
- << "database& db," << endl
- << "const query_base_type& q)"
- << "{"
- << "using namespace " << db << ";"
- << "using odb::details::shared;"
- << "using odb::details::shared_ptr;"
- << endl
- << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << endl
- << "object_statements< object_type >& sts (" << endl
- << "conn.statement_cache ().find_object ());"
- << "shared_ptr st;"
- << endl
- << "query_ (db, q, sts, st);"
- << endl
- << "shared_ptr > r (" << endl
- << "new (shared) " << db <<
- "::result_impl (" << endl
- << "q, st, sts));"
- << endl
- << "return result (r);"
- << "}";
-
- os << "void " << traits << "::" << endl
- << "query_ (database&," << endl
- << "const query_base_type& q," << endl
- << db << "::object_statements< object_type >& sts," << endl
- << "odb::details::shared_ptr<" << db << "::select_statement>& st)"
- << "{"
- << "using namespace " << db << ";"
<< endl
<< "image_type& im (sts.image ());"
<< "binding& imb (sts.out_image_binding ());"
@@ -2781,8 +2729,8 @@ namespace relational
<< "sts.out_image_version (im.version);"
<< "imb.version++;"
<< "}"
- << "st.reset (new (odb::details::shared) select_statement ("
- << endl;
+ << "shared_ptr st (" << endl
+ << "new (shared) select_statement (" << endl;
object_query_statement_ctor_args (c);
@@ -2791,7 +2739,15 @@ namespace relational
post_query_ (c);
- os << "}";
+ os << endl
+ << "shared_ptr > r (" << endl
+ << "new (shared) " << db <<
+ "::result_impl (" << endl
+ << "q, st, sts));"
+ << endl
+ << "return result (r);"
+ << "}";
// erase_query
//
diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx
index 4a2b0ab..8b02e6c 100644
--- a/odb/relational/sqlite/source.cxx
+++ b/odb/relational/sqlite/source.cxx
@@ -512,7 +512,7 @@ namespace relational
<< "// cannot be initialized from an object pointer." << endl
<< "//" << endl
<< member << " = ptr_traits::pointer_type (" << endl
- << "db.load< ptr_traits::element_type > (id));";
+ << "db.load< obj_traits::object_type > (id));";
os << "}"
<< "}";
--
cgit v1.1