aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-04-27 11:36:43 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-04-27 11:36:43 +0200
commit15b1a95942518c84f8161c59820ea5d0e49a4e54 (patch)
tree0a2f6e60622c6085dba00d21e094944526f97d33
parent7e22a444bc360d1b74a25c6d508daea86ca8d5d2 (diff)
Add support for NULL pointers to objects with composite object ids
-rw-r--r--odb/common.cxx1
-rw-r--r--odb/common.hxx7
-rw-r--r--odb/context.cxx15
-rw-r--r--odb/context.hxx9
-rw-r--r--odb/makefile5
-rw-r--r--odb/relational/header.hxx15
-rw-r--r--odb/relational/inline.hxx173
-rw-r--r--odb/relational/model.hxx2
-rw-r--r--odb/relational/mssql/inline.cxx43
-rw-r--r--odb/relational/mysql/inline.cxx43
-rw-r--r--odb/relational/oracle/inline.cxx43
-rw-r--r--odb/relational/pgsql/inline.cxx43
-rw-r--r--odb/relational/source.cxx1
-rw-r--r--odb/relational/source.hxx41
-rw-r--r--odb/relational/sqlite/inline.cxx43
15 files changed, 456 insertions, 28 deletions
diff --git a/odb/common.cxx b/odb/common.cxx
index 28b80cb..0edcb0d 100644
--- a/odb/common.cxx
+++ b/odb/common.cxx
@@ -338,6 +338,7 @@ traverse (semantics::data_member& m,
root_ = &m;
root_id_ = (kp.empty () ? context::id (m) : kp == "id");
root_op_ = (c != 0);
+ root_null_ = context::null (m, kp);
key_prefix_ = kp;
default_name_ = dn;
diff --git a/odb/common.hxx b/odb/common.hxx
index bc45d00..082d78f 100644
--- a/odb/common.hxx
+++ b/odb/common.hxx
@@ -310,10 +310,17 @@ protected:
member_path_, key_prefix_, (root_ != 0 && (root_id_ || root_op_)));
}
+ bool
+ null () const
+ {
+ return (root_ != 0 && root_null_) || context::null (member_path_);
+ }
+
private:
semantics::data_member* root_; // Root member if traversing from a member.
bool root_id_; // True if traversing root as object id.
bool root_op_; // True if traversing root as object pointer.
+ bool root_null_; // True if root is null-able.
private:
void
diff --git a/odb/context.cxx b/odb/context.cxx
index f699f38..693ada4 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -296,6 +296,21 @@ readonly (semantics::data_member& m)
}
bool context::
+null (data_member_path const& mp)
+{
+ // Outer members can override the null-ability of the inner ones. So
+ // start from the most outer member.
+ //
+ for (data_member_path::const_iterator i (mp.begin ()); i != mp.end (); ++i)
+ {
+ if (null (**i))
+ return true;
+ }
+
+ return false;
+}
+
+bool context::
null (semantics::data_member& m)
{
semantics::type& t (utype (m));
diff --git a/odb/context.hxx b/odb/context.hxx
index 2bb91cb..0bb58ba 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -425,12 +425,15 @@ public:
return c.count ("readonly");
}
+ // Null-able.
//
- //
- bool
+ static bool
+ null (data_member_path const&);
+
+ static bool
null (semantics::data_member&);
- bool
+ static bool
null (semantics::data_member&, string const& key_prefix);
// Optimistic concurrency.
diff --git a/odb/makefile b/odb/makefile
index d048065..743ad0b 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -44,6 +44,7 @@ cxx_ptun += \
relational/mssql/common.cxx \
relational/mssql/context.cxx \
relational/mssql/header.cxx \
+relational/mssql/inline.cxx \
relational/mssql/source.cxx \
relational/mssql/model.cxx \
relational/mssql/schema.cxx
@@ -54,6 +55,7 @@ cxx_ptun += \
relational/mysql/common.cxx \
relational/mysql/context.cxx \
relational/mysql/header.cxx \
+relational/mysql/inline.cxx \
relational/mysql/source.cxx \
relational/mysql/model.cxx \
relational/mysql/schema.cxx
@@ -64,6 +66,7 @@ cxx_ptun += \
relational/oracle/common.cxx \
relational/oracle/context.cxx \
relational/oracle/header.cxx \
+relational/oracle/inline.cxx \
relational/oracle/source.cxx \
relational/oracle/model.cxx \
relational/oracle/schema.cxx
@@ -74,6 +77,7 @@ cxx_ptun += \
relational/pgsql/common.cxx \
relational/pgsql/context.cxx \
relational/pgsql/header.cxx \
+relational/pgsql/inline.cxx \
relational/pgsql/source.cxx \
relational/pgsql/model.cxx \
relational/pgsql/schema.cxx
@@ -84,6 +88,7 @@ cxx_ptun += \
relational/sqlite/common.cxx \
relational/sqlite/context.cxx \
relational/sqlite/header.cxx \
+relational/sqlite/inline.cxx \
relational/sqlite/source.cxx \
relational/sqlite/model.cxx \
relational/sqlite/schema.cxx
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index 3d3189e..09a2d39 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -1187,6 +1187,21 @@ namespace relational
<< "init (value_type&, const image_type&, database*);"
<< endl;
+ if (!has_a (c, test_container))
+ {
+ // get_null (image)
+ //
+ os << "static bool" << endl
+ << "get_null (const image_type&);"
+ << endl;
+
+ // set_null (image)
+ //
+ os << "static void" << endl
+ << "set_null (image_type&, " << db << "::statement_kind);"
+ << endl;
+ }
+
os << "};";
}
diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx
index 0c585b8..add4741 100644
--- a/odb/relational/inline.hxx
+++ b/odb/relational/inline.hxx
@@ -75,23 +75,145 @@ namespace relational
};
//
+ // get/set null (composite value only)
+ //
+
+ struct null_member: virtual member_base
+ {
+ typedef null_member base;
+
+ null_member (bool get)
+ : member_base (string (), 0, string (), string ()), get_ (get)
+ {
+ }
+
+ protected:
+ bool get_;
+ };
+
+ template <typename T>
+ struct null_member_impl: null_member, virtual member_base_impl<T>
+ {
+ typedef null_member_impl base_impl;
+
+ null_member_impl (base const& x): base (x) {}
+
+ typedef typename member_base_impl<T>::member_info member_info;
+
+ virtual bool
+ pre (member_info& mi)
+ {
+ // If the whole value type is readonly, then set will never be
+ // called with sk == statement_update.
+ //
+ if (!get_ && !readonly (*context::top_object))
+ {
+ semantics::class_* c;
+
+ if (readonly (mi.m) || ((c = composite (mi.t)) && readonly (*c)))
+ os << "if (sk == statement_insert)" << endl;
+ }
+
+ return true;
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ string traits ("composite_value_traits< " + mi.fq_type () + " >");
+
+ if (get_)
+ os << "r = r && " << traits << "::get_null (" <<
+ "i." << mi.var << "value);";
+ else
+ os << traits << "::set_null (i." << mi.var << "value, sk);";
+ }
+ };
+
+ struct null_base: traversal::class_, virtual context
+ {
+ typedef null_base base;
+
+ null_base (bool get): get_ (get) {}
+
+ virtual void
+ traverse (type& c)
+ {
+ // Ignore transient bases.
+ //
+ if (!composite (c))
+ return;
+
+ string traits ("composite_value_traits< " + class_fq_name (c) + " >");
+
+ // If the derived value type is readonly, then set will never be
+ // called with sk == statement_update.
+ //
+ if (!get_ && readonly (c) && !readonly (*context::top_object))
+ os << "if (sk == statement_insert)" << endl;
+
+ if (get_)
+ os << "r = r && " << traits << "::get_null (i);";
+ else
+ os << traits << "::set_null (i, sk);";
+ }
+
+ protected:
+ bool get_;
+ };
+
+ //
//
struct class_: traversal::class_, virtual context
{
typedef class_ base;
+ class_ ()
+ : get_null_base_ (true),
+ get_null_member_ (true),
+ set_null_base_ (false),
+ set_null_member_ (false)
+ {
+ init ();
+ }
+
+ class_ (class_ const&)
+ : root_context (), //@@ -Wextra
+ context (),
+ get_null_base_ (true),
+ get_null_member_ (true),
+ set_null_base_ (false),
+ set_null_member_ (false)
+ {
+ init ();
+ }
+
+ void
+ init ()
+ {
+ get_null_base_inherits_ >> get_null_base_;
+ get_null_member_names_ >> get_null_member_;
+
+ set_null_base_inherits_ >> set_null_base_;
+ set_null_member_names_ >> set_null_member_;
+ }
+
virtual void
traverse (type& c)
{
if (class_file (c) != unit.file ())
return;
+ context::top_object = context::cur_object = &c;
+
if (object (c))
traverse_object (c);
if (view (c))
traverse_view (c);
else if (composite (c))
traverse_composite (c);
+
+ context::top_object = context::cur_object = 0;
}
virtual void
@@ -504,12 +626,61 @@ namespace relational
}
virtual void
- traverse_composite (type&)
+ traverse_composite (type& c)
{
+ string const& type (class_fq_name (c));
+ string traits ("access::composite_value_traits< " + type + " >");
+
+ os << "// " << class_name (c) << endl
+ << "//" << endl
+ << endl;
+
+ if (!has_a (c, test_container))
+ {
+ // get_null (image)
+ //
+ os << "inline" << endl
+ << "bool " << traits << "::" << endl
+ << "get_null (const image_type& i)"
+ << "{"
+ << "bool r (true);";
+
+ inherits (c, get_null_base_inherits_);
+ names (c, get_null_member_names_);
+
+ os << "return r;"
+ << "}";
+
+ // set_null (image)
+ //
+ os << "inline" << endl
+ << "void " << traits << "::" << endl
+ << "set_null (image_type& i, " << db << "::statement_kind sk)"
+ << "{"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
+ << endl
+ << "using namespace " << db << ";"
+ << endl;
+
+ inherits (c, set_null_base_inherits_);
+ names (c, set_null_member_names_);
+
+ os << "}";
+ }
}
private:
instance<callback_calls> callback_calls_;
+
+ instance<null_base> get_null_base_;
+ traversal::inherits get_null_base_inherits_;
+ instance<null_member> get_null_member_;
+ traversal::names get_null_member_names_;
+
+ instance<null_base> set_null_base_;
+ traversal::inherits set_null_base_inherits_;
+ instance<null_member> set_null_member_;
+ traversal::names set_null_member_names_;
};
struct include: virtual context
diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx
index afaa90d..d41b701 100644
--- a/odb/relational/model.hxx
+++ b/odb/relational/model.hxx
@@ -102,7 +102,7 @@ namespace relational
traverse_column (semantics::data_member& m, string const& name, bool)
{
bool id (object_columns_base::id ()); // Id or part of.
- bool null (!id && context::null (m, key_prefix_));
+ bool null (!id && object_columns_base::null ());
string col_id (id_prefix_ +
(key_prefix_.empty () ? m.name () : key_prefix_));
diff --git a/odb/relational/mssql/inline.cxx b/odb/relational/mssql/inline.cxx
new file mode 100644
index 0000000..d49fbfa
--- /dev/null
+++ b/odb/relational/mssql/inline.cxx
@@ -0,0 +1,43 @@
+// file : odb/relational/mssql/inline.cxx
+// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <odb/relational/inline.hxx>
+
+#include <odb/relational/mssql/common.hxx>
+#include <odb/relational/mssql/context.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace mssql
+ {
+ namespace inline_
+ {
+ namespace relational = relational::inline_;
+
+ struct null_member: relational::null_member_impl<sql_type>,
+ member_base
+ {
+ null_member (base const& x)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
+ {
+ }
+
+ virtual void
+ traverse_simple (member_info& mi)
+ {
+ if (get_)
+ os << "r = r && i." << mi.var << "size_ind == SQL_NULL_DATA;";
+ else
+ os << "i." << mi.var << "size_ind = SQL_NULL_DATA;";
+ }
+ };
+ entry<null_member> null_member_;
+ }
+ }
+}
diff --git a/odb/relational/mysql/inline.cxx b/odb/relational/mysql/inline.cxx
new file mode 100644
index 0000000..f9a02a9
--- /dev/null
+++ b/odb/relational/mysql/inline.cxx
@@ -0,0 +1,43 @@
+// file : odb/relational/mysql/inline.cxx
+// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <odb/relational/inline.hxx>
+
+#include <odb/relational/mysql/common.hxx>
+#include <odb/relational/mysql/context.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace mysql
+ {
+ namespace inline_
+ {
+ namespace relational = relational::inline_;
+
+ struct null_member: relational::null_member_impl<sql_type>,
+ member_base
+ {
+ null_member (base const& x)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
+ {
+ }
+
+ virtual void
+ traverse_simple (member_info& mi)
+ {
+ if (get_)
+ os << "r = r && i." << mi.var << "null;";
+ else
+ os << "i." << mi.var << "null = 1;";
+ }
+ };
+ entry<null_member> null_member_;
+ }
+ }
+}
diff --git a/odb/relational/oracle/inline.cxx b/odb/relational/oracle/inline.cxx
new file mode 100644
index 0000000..5f69fa8
--- /dev/null
+++ b/odb/relational/oracle/inline.cxx
@@ -0,0 +1,43 @@
+// file : odb/relational/oracle/inline.cxx
+// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <odb/relational/inline.hxx>
+
+#include <odb/relational/oracle/common.hxx>
+#include <odb/relational/oracle/context.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace oracle
+ {
+ namespace inline_
+ {
+ namespace relational = relational::inline_;
+
+ struct null_member: relational::null_member_impl<sql_type>,
+ member_base
+ {
+ null_member (base const& x)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
+ {
+ }
+
+ virtual void
+ traverse_simple (member_info& mi)
+ {
+ if (get_)
+ os << "r = r && i." << mi.var << "indicator == -1;";
+ else
+ os << "i." << mi.var << "indicator = -1;";
+ }
+ };
+ entry<null_member> null_member_;
+ }
+ }
+}
diff --git a/odb/relational/pgsql/inline.cxx b/odb/relational/pgsql/inline.cxx
new file mode 100644
index 0000000..ece021a
--- /dev/null
+++ b/odb/relational/pgsql/inline.cxx
@@ -0,0 +1,43 @@
+// file : odb/relational/pgsql/inline.cxx
+// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <odb/relational/inline.hxx>
+
+#include <odb/relational/pgsql/common.hxx>
+#include <odb/relational/pgsql/context.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace pgsql
+ {
+ namespace inline_
+ {
+ namespace relational = relational::inline_;
+
+ struct null_member: relational::null_member_impl<sql_type>,
+ member_base
+ {
+ null_member (base const& x)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
+ {
+ }
+
+ virtual void
+ traverse_simple (member_info& mi)
+ {
+ if (get_)
+ os << "r = r && i." << mi.var << "null;";
+ else
+ os << "i." << mi.var << "null = true;";
+ }
+ };
+ entry<null_member> null_member_;
+ }
+ }
+}
diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx
index 5bf14f1..eb909ce 100644
--- a/odb/relational/source.cxx
+++ b/odb/relational/source.cxx
@@ -79,7 +79,6 @@ traverse_object (type& c)
if (containers)
{
- containers = true;
size_t scn (has_a (c, test_straight_container));
if (scn != 0)
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index bbea0a7..594274a 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -1266,10 +1266,10 @@ namespace relational
os << "}"
<< "else" << endl;
- // @@ Composite value currently cannot be NULL.
- //
- if (!null (mi.m, key_prefix_) || composite (mi.t))
+ if (!null (mi.m, key_prefix_))
os << "throw null_pointer ();";
+ else if (composite (mi.t))
+ os << traits << "::set_null (i." << mi.var << "value, sk);";
else
set_null (mi);
}
@@ -1456,22 +1456,23 @@ namespace relational
" > ptr_traits;"
<< endl;
- // @@ Composite value currently cannot be NULL.
- //
- if (!comp)
- {
- os << "if (";
+ os << "if (";
+
+ if (comp)
+ os << "composite_value_traits< " + type + " >::get_null (i." <<
+ mi.var << "value)";
+ else
get_null (mi);
- os << ")" << endl;
- if (!null (mi.m, key_prefix_) )
- os << "throw null_pointer ();";
- else
- os << member << " = ptr_traits::pointer_type ();";
+ os << ")" << endl;
- os << "else"
- << "{";
- }
+ if (!null (mi.m, key_prefix_) )
+ os << "throw null_pointer ();";
+ else
+ os << member << " = ptr_traits::pointer_type ();";
+
+ os << "else"
+ << "{";
os << type << " id;";
@@ -1542,12 +1543,8 @@ namespace relational
}
}
- // @@ Composite value currently cannot be NULL.
- //
- if (!composite (mi.t))
- os << "}";
-
- os << "}";
+ os << "}"
+ << "}";
}
}
diff --git a/odb/relational/sqlite/inline.cxx b/odb/relational/sqlite/inline.cxx
new file mode 100644
index 0000000..f4dc377
--- /dev/null
+++ b/odb/relational/sqlite/inline.cxx
@@ -0,0 +1,43 @@
+// file : odb/relational/sqlite/inline.cxx
+// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <odb/relational/inline.hxx>
+
+#include <odb/relational/sqlite/common.hxx>
+#include <odb/relational/sqlite/context.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace sqlite
+ {
+ namespace inline_
+ {
+ namespace relational = relational::inline_;
+
+ struct null_member: relational::null_member_impl<sql_type>,
+ member_base
+ {
+ null_member (base const& x)
+ : member_base::base (x), // virtual base
+ member_base::base_impl (x), // virtual base
+ base_impl (x),
+ member_base (x)
+ {
+ }
+
+ virtual void
+ traverse_simple (member_info& mi)
+ {
+ if (get_)
+ os << "r = r && i." << mi.var << "null;";
+ else
+ os << "i." << mi.var << "null = true;";
+ }
+ };
+ entry<null_member> null_member_;
+ }
+ }
+}