aboutsummaryrefslogtreecommitdiff
path: root/odb
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-07-04 17:53:47 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-07-04 17:53:47 +0200
commit932cd7a53b3996468fee5cfa63c2b2998dbe971a (patch)
tree55424fe09a95310bc2b8e6d1473108b64107e06c /odb
parent1ac1ae65e6cbf42c002acb27615127bbc0b20d9e (diff)
Implement support for database operations callbacks
New object pragma: callback. New test: common/callback. New manual section: 10.1.4, "callback".
Diffstat (limited to 'odb')
-rw-r--r--odb/header.cxx1
-rw-r--r--odb/pragma.cxx38
-rw-r--r--odb/relational/header.hxx11
-rw-r--r--odb/relational/inline.hxx90
-rw-r--r--odb/relational/source.hxx6
-rw-r--r--odb/tracer/header.cxx10
-rw-r--r--odb/tracer/inline.cxx14
-rw-r--r--odb/validator.cxx43
8 files changed, 210 insertions, 3 deletions
diff --git a/odb/header.cxx b/odb/header.cxx
index 140a781..62902f6 100644
--- a/odb/header.cxx
+++ b/odb/header.cxx
@@ -88,6 +88,7 @@ namespace header
os << "#include <odb/core.hxx>" << endl
<< "#include <odb/traits.hxx>" << endl
+ << "#include <odb/callback.hxx>" << endl
<< "#include <odb/pointer-traits.hxx>" << endl;
// In case of a boost TR1 implementation, we cannot distinguish
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index a22c1d1..3b8d222 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -127,7 +127,8 @@ check_decl_type (tree d, string const& name, string const& p, location_t l)
}
else if (p == "object" ||
p == "pointer" ||
- p == "abstract")
+ p == "abstract" ||
+ p == "callback")
{
if (tc != RECORD_TYPE)
{
@@ -374,6 +375,41 @@ handle_pragma (cpp_reader* reader,
tt = pragma_lex (&t);
}
+ else if (p == "callback")
+ {
+ // callback (name)
+ //
+
+ // Make sure we've got the correct declaration type.
+ //
+ if (decl != 0 && !check_decl_type (decl, decl_name, p, loc))
+ return;
+
+ if (pragma_lex (&t) != CPP_OPEN_PAREN)
+ {
+ error () << "'(' expected after db pragma '" << p << "'" << endl;
+ return;
+ }
+
+ tt = pragma_lex (&t);
+
+ if (tt != CPP_NAME)
+ {
+ error () << "member function name expected in db pragma '" << p
+ << "'" << endl;
+ return;
+ }
+
+ val = IDENTIFIER_POINTER (t);
+
+ if (pragma_lex (&t) != CPP_CLOSE_PAREN)
+ {
+ error () << "')' expected at the end of db pragma '" << p << "'" << endl;
+ return;
+ }
+
+ tt = pragma_lex (&t);
+ }
else if (p == "id")
{
// id
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index 16c7855..62c2e92 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -940,6 +940,16 @@ namespace relational
// Functions (concrete).
//
+ // callback ()
+ //
+ os << "static void" << endl
+ << "callback (database&, object_type&, callback_event);"
+ << endl;
+
+ os << "static void" << endl
+ << "callback (database&, const object_type&, callback_event);"
+ << endl;
+
// persist ()
//
os << "static void" << endl
@@ -1090,6 +1100,7 @@ namespace relational
generate ()
{
os << "#include <odb/details/buffer.hxx>" << endl
+ << "#include <odb/details/unused.hxx>" << endl
<< endl;
os << "#include <odb/" << db << "/version.hxx>" << endl
diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx
index 856965c..89fc720 100644
--- a/odb/relational/inline.hxx
+++ b/odb/relational/inline.hxx
@@ -13,6 +13,67 @@ namespace relational
{
namespace inline_
{
+ //
+ //
+ struct callback_calls: traversal::class_, virtual context
+ {
+ typedef callback_calls base;
+
+ callback_calls ()
+ {
+ *this >> inherits_ >> *this;
+ }
+
+ callback_calls (callback_calls const&)
+ : root_context (), //@@ -Wextra
+ context ()
+ {
+ *this >> inherits_ >> *this;
+ }
+
+ virtual void
+ traverse (type& c, bool constant)
+ {
+ const_ = constant;
+ traverse (c);
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ // Ignore transient bases.
+ //
+ if (!c.count ("object"))
+ return;
+
+ if (c.count ("callback"))
+ {
+ string name (c.get<string> ("callback"));
+
+ // In case of the const object, we only generate the call if
+ // there is a const callback.
+ //
+ if (const_)
+ {
+ if (c.count ("callback-const"))
+ os << "static_cast< const " << c.fq_name () << "& > (obj)." <<
+ name << " (e, db);";
+ }
+ else
+ os << "static_cast< " << c.fq_name () << "& > (obj)." <<
+ name << " (e, db);";
+ }
+ else
+ inherits (c);
+ }
+
+ protected:
+ bool const_;
+ traversal::inherits inherits_;
+ };
+
+ //
+ //
struct class_: traversal::class_, virtual context
{
typedef class_ base;
@@ -113,6 +174,32 @@ namespace relational
if (abst)
return;
+ // callback ()
+ //
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "callback (database& db, object_type& obj, callback_event e)"
+ << endl
+ << "{"
+ << "ODB_POTENTIALLY_UNUSED (db);"
+ << "ODB_POTENTIALLY_UNUSED (obj);"
+ << "ODB_POTENTIALLY_UNUSED (e);"
+ << endl;
+ callback_calls_->traverse (c, false);
+ os << "}";
+
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "callback (database& db, const object_type& obj, " <<
+ "callback_event e)"
+ << "{"
+ << "ODB_POTENTIALLY_UNUSED (db);"
+ << "ODB_POTENTIALLY_UNUSED (obj);"
+ << "ODB_POTENTIALLY_UNUSED (e);"
+ << endl;
+ callback_calls_->traverse (c, true);
+ os << "}";
+
// query_type
//
if (options.generate_query ())
@@ -164,6 +251,9 @@ namespace relational
*/
}
+
+ private:
+ instance<callback_calls> callback_calls_;
};
}
}
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index 4d2f10a..42d0f9b 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -2331,9 +2331,11 @@ namespace relational
<< endl
<< "if (l.locked ())"
<< "{"
+ << "callback (db, obj, callback_event::pre_load);"
<< "init (obj, sts.image (), db);"
<< "load_ (sts, obj);"
<< "sts.load_delayed ();"
+ << "callback (db, obj, callback_event::post_load);"
<< "l.unlock ();"
<< "}"
<< "else" << endl
@@ -2367,9 +2369,11 @@ namespace relational
<< endl
<< "if (l.locked ())"
<< "{"
+ << "callback (db, obj, callback_event::pre_load);"
<< "init (obj, sts.image (), db);"
<< "load_ (sts, obj);"
<< "sts.load_delayed ();"
+ << "callback (db, obj, callback_event::post_load);"
<< "l.unlock ();"
<< "}"
<< "else" << endl
@@ -2689,8 +2693,6 @@ namespace relational
if (embedded_schema)
os << "#include <odb/schema-catalog-impl.hxx>" << endl;
- os << "#include <odb/details/unused.hxx>" << endl;
-
if (options.generate_query ())
os << "#include <odb/details/shared-ptr.hxx>" << endl;
diff --git a/odb/tracer/header.cxx b/odb/tracer/header.cxx
index 16bee82..ac89ec7 100644
--- a/odb/tracer/header.cxx
+++ b/odb/tracer/header.cxx
@@ -88,6 +88,16 @@ namespace tracer
os << "static bool" << endl
<< "find (database&, const id_type&, object_type&);";
+ // callback ()
+ //
+ os << "static void" << endl
+ << "callback (database&, object_type&, callback_event);"
+ << endl;
+
+ os << "static void" << endl
+ << "callback (database&, const object_type&, callback_event);"
+ << endl;
+
os << "};";
}
};
diff --git a/odb/tracer/inline.cxx b/odb/tracer/inline.cxx
index f4125a9..e8feec8 100644
--- a/odb/tracer/inline.cxx
+++ b/odb/tracer/inline.cxx
@@ -42,6 +42,20 @@ namespace tracer
<< "{"
<< "return obj." << id.name () << ";" << endl
<< "}";
+
+ // callback ()
+ //
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "callback (database&, object_type&, callback_event)"
+ << "{"
+ << "}";
+
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "callback (database&, const object_type&, callback_event)"
+ << "{"
+ << "}";
}
};
}
diff --git a/odb/validator.cxx b/odb/validator.cxx
index 998bd8b..487d69a 100644
--- a/odb/validator.cxx
+++ b/odb/validator.cxx
@@ -3,6 +3,8 @@
// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
+#include <odb/gcc.hxx>
+
#include <iostream>
#include <odb/traversal.hxx>
@@ -138,6 +140,47 @@ namespace
virtual void
traverse_object (type& c)
{
+ // Check that the callback function exist.
+ //
+ if (c.count ("callback"))
+ {
+ string name (c.get<string> ("callback"));
+ tree decl (
+ lookup_qualified_name (
+ c.tree_node (), get_identifier (name.c_str ()), false, false));
+
+ if (decl == error_mark_node || TREE_CODE (decl) != BASELINK)
+ {
+ cerr << c.file () << ":" << c.line () << ":" << c.column () << ": "
+ << "error: unable to resolve member function '" << name << "' "
+ << "specified with '#pragma db callback' for class '"
+ << c.name () << "'" << endl;
+
+ valid_ = false;
+ }
+
+ // Figure out if we have a const version of the callback. 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));
+ if (DECL_CONST_MEMFUNC_P (f))
+ {
+ c.set ("callback-const", true);
+ break;
+ }
+ }
+
+ //@@ Would be nice to check the signature of the function(s)
+ // instead of postponing it until the C++ compilation. Though
+ // we may still get C++ compilation errors because of const
+ // mismatch.
+ //
+ }
+
+ // Check bases.
+ //
bool base (false);
for (type::inherits_iterator i (c.inherits_begin ());