diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2012-04-26 11:29:05 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2012-04-26 11:29:05 +0200 |
commit | 8e046e3ea7e88f872205c2b65cb7f9b86aaabd93 (patch) | |
tree | aba1ae331454eb1e0cf9525faf8a084d3652bda0 | |
parent | 6c88333c2e0232aed9e0b3c9077306f09e36c65c (diff) |
Make session optional
-rw-r--r-- | NEWS | 8 | ||||
-rw-r--r-- | doc/manual.xhtml | 136 | ||||
-rw-r--r-- | odb/context.hxx | 6 | ||||
-rw-r--r-- | odb/features.hxx | 1 | ||||
-rw-r--r-- | odb/header.cxx | 5 | ||||
-rw-r--r-- | odb/options.cli | 11 | ||||
-rw-r--r-- | odb/pragma.cxx | 47 | ||||
-rw-r--r-- | odb/relational/header.cxx | 40 | ||||
-rw-r--r-- | odb/relational/processor.cxx | 66 | ||||
-rw-r--r-- | odb/relational/source.hxx | 2 | ||||
-rw-r--r-- | odb/validator.cxx | 37 |
11 files changed, 310 insertions, 49 deletions
@@ -50,6 +50,14 @@ Version 1.9.0 but one is not used. For more information, refer to Section 6.2, "Bidirectional Relationships" in the ODB manual. + * Session support is now optional and is disabled by default. This is a + backwards-incompatible change. Session support can be enabled on the + per object basis or at the namespace level using the new session pragma. + It can also be enabled by default for all the objects using the + --generate-session ODB compiler option. Thus to get the old behavior + where all the objects were session-enabled, simply add --generate-session + to your ODB compiler command line. + Version 1.8.0 * Support for the Microsoft SQL Server database. The provided connection diff --git a/doc/manual.xhtml b/doc/manual.xhtml index cad568c..766844f 100644 --- a/doc/manual.xhtml +++ b/doc/manual.xhtml @@ -457,6 +457,7 @@ for consistency. <tr><th>12.1.7</th><td><a href="#12.1.7"><code>callback</code></a></td></tr> <tr><th>12.1.8</th><td><a href="#12.1.8"><code>schema</code></a></td></tr> <tr><th>12.1.9</th><td><a href="#12.1.9"><code>polymorphic</code></a></td></tr> + <tr><th>12.1.10</th><td><a href="#12.1.10"><code>session</code></a></td></tr> </table> </td> </tr> @@ -535,6 +536,7 @@ for consistency. <tr><th>12.5.1</th><td><a href="#12.5.1"><code>pointer</code></a></td></tr> <tr><th>12.5.2</th><td><a href="#12.5.2"><code>table</code></a></td></tr> <tr><th>12.5.3</th><td><a href="#12.5.3"><code>schema</code></a></td></tr> + <tr><th>12.5.4</th><td><a href="#12.5.4"><code>session</code></a></td></tr> </table> </td> </tr> @@ -6090,8 +6092,10 @@ class person <p>However, a value type that can be used as an object id has a number of restrictions. Such a value type cannot have container, object pointer, or read-only data members. It also must be - default-constructible and implement the less-than comparison operator - (<code>operator<</code>).</p> + default-constructible. Furthermore, if the persistent class in which + this composite value type is used as object id has session support + enabled (<a href="#10">Chapter 10, "Session"</a>), then it must also + implement the less-than comparison operator (<code>operator<</code>).</p> <h3><a name="7.2.2">7.2.2 Composite Value Column and Table Names</a></h3> @@ -6848,6 +6852,11 @@ class contractor: public person }; </pre> + <p>Similarly, if we enable or disable session support + (<a href="#10">Chapter 10, "Session"</a>) for the root class, then + the ODB compiler will automatically enable or disable it for all + the derived classes.</p> + <p>For polymorphic persistent classes, all the database operations can be performed on objects with different static and dynamic types. Similarly, operations that load persistent objects from the @@ -8258,6 +8267,50 @@ struct employee_name object cache. In future versions it will provide additional functionality, such as automatic object state change tracking.</p> + <p>Session support is optional and can be enabled or disabled on the + per object basis using the <code>db session</code> pragma, for + example:</p> + + <pre class="c++"> +#pragma db object session +class person +{ + ... +}; + </pre> + + <p>We can also enable or disable session support for a group of + objects at the namespace level:</p> + + <pre class="c++"> +#pragma db namespace session +namespace accounting +{ + #pragma db object // Session support is enabled. + class employee + { + ... + }; + + #pragma db object session(false) // Session support is disabled. + class employer + { + ... + }; +} + </pre> + + <p>Finally, we can pass the <code>--generate-session</code> ODB compiler + option to enable session support by default. With this option session + support will be enabled for all the persistent classes except those + for which it was explicitly disabled using the + <code>db session</code>. An alternative to this method with the + same effect is to enable session support for the global namespace:</p> + + <pre class="c++"> +#pragma db namespace() session + </pre> + <p>Each thread of execution in an application can have only one active session at a time. A session is started by creating an instance of the <code>odb::session</code> class and is automatically terminated @@ -8374,8 +8427,8 @@ namespace odb <h2><a name="10.1">10.1 Object Cache</a></h2> - <p>A session is an object cache. Every time an object is made persistent - by calling the <code>database::persist()</code> function + <p>A session is an object cache. Every time a session-enabled object is + made persistent by calling the <code>database::persist()</code> function (<a href="#3.7">Section 3.7, "Making Objects Persistent"</a>), loaded by calling the <code>database::load()</code> or <code>database::find()</code> function (<a href="#3.8">Section 3.8, "Loading Persistent Objects"</a>), @@ -8991,6 +9044,12 @@ class person <td><a href="#12.1.9">12.1.9</a></td> </tr> + <tr> + <td><code>session</code></td> + <td>enable/disable session support for a persistent class</td> + <td><a href="#12.1.10">12.1.10</a></td> + </tr> + </table> <h3><a name="12.1.1">12.1.1 <code>table</code></a></h3> @@ -9549,6 +9608,38 @@ class employee class is polymorphic. For more information on polymorphism support, refer to <a href="#8">Chapter 8, "Inheritance"</a>.</p> + <h3><a name="12.1.10">12.1.10 <code>session</code></a></h3> + + <p>The <code>session</code> specifier specifies whether to enable + session support for a persistent class. For example:</p> + + <pre class="c++"> +#pragma db object session // Enable. +class person +{ + ... +}; + +#pragma db object session(true) // Enable. +class employee +{ + ... +}; + +#pragma db object session(false) // Disable. +class employer +{ + ... +}; + </pre> + + <p>Session support is disabled by default unless the + <code>--generate-session</code> ODB compiler option is specified + or session support is enabled at the namespace level + (<a href="#12.5.4">Section 12.5.4, "<code>session</code>"</a>). + For more information on sessions, refer to <a href="#10">Chapter + 10, "Session"</a>.</p> + <h2><a name="12.2">12.2 View Type Pragmas</a></h2> <p>A pragma with the <code>view</code> qualifier declares a C++ class @@ -11380,6 +11471,12 @@ namespace test <td><a href="#12.5.3">12.5.3</a></td> </tr> + <tr> + <td><code>session</code></td> + <td>enable/disable session support for persistent classes inside a namespace</td> + <td><a href="#12.5.4">12.5.4</a></td> + </tr> + </table> <h3><a name="12.5.1">12.5.1 <code>pointer</code></a></h3> @@ -11507,6 +11604,37 @@ class employer For more information on specifying a database schema refer to <a href="#12.1.8">Section 12.1.8, "<code>schema</code>"</a>.</p> + <h3><a name="12.5.4">12.5.4 <code>session</code></a></h3> + + <p>The <code>session</code> specifier specifies whether to enable + session support for persistent classes inside a namespace. For + example:</p> + + <pre class="c++"> +#pragma db namespace session +namespace hr +{ + #pragma db object // Enabled. + class employee + { + ... + }; + + #pragma db object session(false) // Disabled. + class employer + { + ... + }; +} + </pre> + + <p>Session support is disabled by default unless the + <code>--generate-session</code> ODB compiler option is specified. + Session support specified at the namespace level can be overridden + on the per object basis (<a href="#12.1.10">Section 12.1.10, + "<code>session</code>"</a>). For more information on sessions, + refer to <a href="#10">Chapter 10, "Session"</a>.</p> + <h2><a name="12.6">12.6 C++ Compiler Warnings</a></h2> <p>When a C++ header file defining persistent classes and containing diff --git a/odb/context.hxx b/odb/context.hxx index cdb49ac..2bb91cb 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -381,6 +381,12 @@ public: } static bool + session (semantics::class_& c) + { + return c.get<bool> ("session"); + } + + static bool transient (semantics::data_member& m) { return m.count ("transient"); diff --git a/odb/features.hxx b/odb/features.hxx index 0468acb..359d99e 100644 --- a/odb/features.hxx +++ b/odb/features.hxx @@ -18,6 +18,7 @@ struct features bool simple_object; bool polymorphic_object; bool no_id_object; + bool session_object; bool view; }; diff --git a/odb/header.cxx b/odb/header.cxx index a2b3b96..8e6718d 100644 --- a/odb/header.cxx +++ b/odb/header.cxx @@ -46,6 +46,11 @@ namespace header os << "#include <odb/container-traits.hxx>" << endl; + if (ctx.features.session_object) + os << "#include <odb/cache-traits.hxx>" << endl; + else + os << "#include <odb/no-op-cache-traits.hxx>" << endl; + if (ctx.features.polymorphic_object) os << "#include <odb/polymorphic-info.hxx>" << endl; diff --git a/odb/options.cli b/odb/options.cli index 95a5d4c..d205039 100644 --- a/odb/options.cli +++ b/odb/options.cli @@ -54,8 +54,15 @@ class options bool --generate-query | -q { - "Generate query support code. Without this support you cannot use - views and can only load objects via their ids." + "Generate query support code. Without this support you cannot use views + and can only load objects via their ids." + }; + + bool --generate-session | -e + { + "Generate session support code. With this option session support will + be enabled by default for all the persistent classes except those for + which it was explicitly disabled using the \cb{db session} pragma." }; bool --generate-schema | -s diff --git a/odb/pragma.cxx b/odb/pragma.cxx index 698551a..e2dc4cc 100644 --- a/odb/pragma.cxx +++ b/odb/pragma.cxx @@ -493,6 +493,17 @@ check_spec_decl_type (tree d, return false; } } + else if (p == "session") + { + // Session can be used only for namespaces and objects. + // + if (tc != NAMESPACE_DECL && !CLASS_TYPE_P (d)) + { + error (l) << "name '" << name << "' in db pragma " << p << " does " + << "not refer to a namespace or class" << endl; + return false; + } + } else if (p == "schema") { // For now schema can be used only for namespaces and objects. @@ -727,6 +738,42 @@ handle_pragma (cpp_reader* reader, tt = pragma_lex (&t); } + else if (p == "session") + { + // session + // session (true|false) + // + + // Make sure we've got the correct declaration type. + // + if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + return; + + tt = pragma_lex (&t); + + if (tt == CPP_OPEN_PAREN) + { + tt = pragma_lex (&t); + + string s; + if (tt != CPP_NAME || + ((s = IDENTIFIER_POINTER (t)) != "true" && s != "false")) + { + error () << "true or false expected in db pragma " << p << endl; + return; + } + + tt = pragma_lex (&t); + if (tt != CPP_CLOSE_PAREN) + { + error () << "')' expected at the end of db pragma " << p << endl; + return; + } + + val = (s == "true"); + tt = pragma_lex (&t); + } + } else if (p == "schema") { // schema (<name>) diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx index 46ba722..48bca91 100644 --- a/odb/relational/header.cxx +++ b/odb/relational/header.cxx @@ -384,25 +384,31 @@ traverse_object (type& c) << "reference_cache_traits;" << endl; } - else if (poly_derived) - { - os << "typedef" << endl - << "odb::pointer_cache_traits<root_traits::pointer_type>" << endl - << "pointer_cache_traits;" - << "typedef" << endl - << "odb::reference_cache_traits<root_type>" << endl - << "reference_cache_traits;" - << endl; - } else { - os << "typedef" << endl - << "odb::pointer_cache_traits<pointer_type>" << endl - << "pointer_cache_traits;" - << "typedef" << endl - << "odb::reference_cache_traits<object_type>" << endl - << "reference_cache_traits;" - << endl; + char const* p (session (c) ? "" : "no_op_"); + + if (poly_derived) + { + os << "typedef" << endl + << "odb::" << p << "pointer_cache_traits<" << + "root_traits::pointer_type>" << endl + << "pointer_cache_traits;" + << "typedef" << endl + << "odb::" << p << "reference_cache_traits<root_type>" << endl + << "reference_cache_traits;" + << endl; + } + else + { + os << "typedef" << endl + << "odb::" << p << "pointer_cache_traits<pointer_type>" << endl + << "pointer_cache_traits;" + << "typedef" << endl + << "odb::" << p << "reference_cache_traits<object_type>" << endl + << "reference_cache_traits;" + << endl; + } } // Statements typedefs. diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx index cdacfd4..c45d71f 100644 --- a/odb/relational/processor.cxx +++ b/odb/relational/processor.cxx @@ -1820,13 +1820,63 @@ namespace relational virtual void traverse_object_pre (type& c) { - if (semantics::class_* root = polymorphic (c)) + semantics::class_* poly_root (polymorphic (c)); + + // Determine whether it is a session object. + // + if (!c.count ("session")) + { + // If this is a derived class in a polymorphic hierarchy, + // then it should have the same session value as the root. + // + if (poly_root != 0 && poly_root != &c) + c.set ("session", session (*poly_root)); + else + { + // See if any of the namespaces containing this class specify + // the session value. + // + bool found (false); + for (semantics::scope* s (&c.scope ());; s = &s->scope_ ()) + { + using semantics::namespace_; + + namespace_* ns (dynamic_cast<namespace_*> (s)); + + if (ns == 0) + continue; // Some other scope. + + if (ns->extension ()) + ns = &ns->original (); + + if (ns->count ("session")) + { + c.set ("session", ns->get<bool> ("session")); + found = true; + break; + } + + if (ns->global_scope ()) + break; + } + + // If still not found, then use the default value. + // + if (!found) + c.set ("session", options.generate_session ()); + } + } + + if (session (c)) + features.session_object = true; + + if (poly_root != 0) { using namespace semantics; - semantics::data_member& idm (*id_member (*root)); + semantics::data_member& idm (*id_member (*poly_root)); - if (root != &c) + if (poly_root != &c) { // If we are a derived class in the polymorphic persistent // class hierarchy, then add a synthesized virtual pointer @@ -1846,23 +1896,23 @@ namespace relational // Use the raw pointer as this member's type. // - if (!root->pointed_p ()) + if (!poly_root->pointed_p ()) { // Create the pointer type in the graph. The pointer node // in GCC seems to always be present, even if not explicitly // used in the translation unit. // - tree t (root->tree_node ()); + tree t (poly_root->tree_node ()); tree ptr (TYPE_POINTER_TO (t)); assert (ptr != 0); ptr = TYPE_MAIN_VARIANT (ptr); pointer& p (unit.new_node<pointer> (f, l, col, ptr)); unit.insert (ptr, p); - unit.new_edge<points> (p, *root); - assert (root->pointed_p ()); + unit.new_edge<points> (p, *poly_root); + assert (poly_root->pointed_p ()); } - unit.new_edge<belongs> (m, root->pointed ().pointer ()); + unit.new_edge<belongs> (m, poly_root->pointed ().pointer ()); m.set ("not-null", true); m.set ("deferred", false); diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index 42ff235..bbea0a7 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -3368,8 +3368,6 @@ namespace relational os << endl; - os << "#include <odb/cache-traits.hxx>" << endl; - if (features.polymorphic_object) os << "#include <odb/polymorphic-map.hxx>" << endl; diff --git a/odb/validator.cxx b/odb/validator.cxx index d346b25..eac5086 100644 --- a/odb/validator.cxx +++ b/odb/validator.cxx @@ -1047,7 +1047,7 @@ namespace if (id != 0) { - if (semantics::class_* c = composite_wrapper (utype (*id))) + if (semantics::class_* cm = composite_wrapper (utype (*id))) { // Composite id cannot be auto. // @@ -1065,7 +1065,7 @@ namespace // if (valid_) { - composite_id_members_.traverse (*c); + composite_id_members_.traverse (*cm); if (!valid_) os << id->file () << ":" << id->line () << ":" << id->column () @@ -1074,28 +1074,29 @@ namespace // Check that the composite value type is default-constructible. // - if (!c->default_ctor ()) + if (!cm->default_ctor ()) { - os << c->file () << ":" << c->line () << ":" << c->column () + os << cm->file () << ":" << cm->line () << ":" << cm->column () << ": error: composite value type that is used as object id " << "is not default-constructible" << endl; - os << c->file () << ":" << c->line () << ":" << c->column () - << ": info: provide default constructor for this value type" - << endl; + os << cm->file () << ":" << cm->line () << ":" << cm->column () + << ": info: provide default constructor for this value type" + << endl; - os << id->file () << ":" << id->line () << ":" << id->column () - << ": info: composite id is defined here" << endl; + os << id->file () << ":" << id->line () << ":" << id->column () + << ": info: composite id is defined here" << endl; - valid_ = false; + valid_ = false; } - // Check that composite values can be compared (used in session). + // If this is a session object, make sure that the composite + // value can be compared. // - if (has_lt_operator_ != 0) + if (session (c) && has_lt_operator_ != 0) { tree args (make_tree_vec (1)); - TREE_VEC_ELT (args, 0) = c->tree_node (); + TREE_VEC_ELT (args, 0) = cm->tree_node (); tree inst ( instantiate_template ( @@ -1126,17 +1127,21 @@ namespace if (!v) { - os << c->file () << ":" << c->line () << ":" << c->column () + os << cm->file () << ":" << cm->line () << ":" << cm->column () << ": error: composite value type that is used as object id " - << "does not support the less than (<) comparison" + << "in persistent class with session support does not " + << "define the less than (<) comparison" << endl; - os << c->file () << ":" << c->line () << ":" << c->column () + os << cm->file () << ":" << cm->line () << ":" << cm->column () << ": info: provide operator< for this value type" << endl; os << id->file () << ":" << id->line () << ":" << id->column () << ": info: composite id is defined here" << endl; + os << c.file () << ":" << c.line () << ":" << c.column () + << ": info: persistent class is defined here" << endl; + valid_ = false; } } |