summaryrefslogtreecommitdiff
path: root/odb
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-10-11 16:52:45 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-10-21 19:25:06 +0200
commitb2f0cd834b8f5651985357f8acbe82edd7d11c63 (patch)
tree591f652e2f49631a0920828598eba4fff28fcfc8 /odb
parent5ff1382aeae38946889b1e09a21bde1c48475dfd (diff)
Split 'in' binding into insert/update pair; rename 'out' to select
Also add the initial infrastructure for the readonly members support. Right now the split insert/update bindings allows us to avoid sending object id in UPDATE statements. It will also allows us to support readonly members.
Diffstat (limited to 'odb')
-rw-r--r--odb/context.cxx60
-rw-r--r--odb/context.hxx47
-rw-r--r--odb/relational/context.hxx8
-rw-r--r--odb/relational/header.hxx143
-rw-r--r--odb/relational/mysql/source.cxx61
-rw-r--r--odb/relational/oracle/source.cxx55
-rw-r--r--odb/relational/pgsql/header.cxx21
-rw-r--r--odb/relational/pgsql/source.cxx111
-rw-r--r--odb/relational/source.hxx295
-rw-r--r--odb/relational/sqlite/source.cxx56
10 files changed, 598 insertions, 259 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
index fec6457..45dd55b 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -968,61 +968,61 @@ namespace
{
struct column_count_impl: object_members_base
{
- column_count_impl (bool out)
- : out_ (out), count_ (0)
- {
- }
+ typedef context::column_count_type count_type;
virtual void
traverse (semantics::class_& c)
{
- char const* key (out_ ? "out-column-count" : "in-column-count");
+ if (c.count ("column-count"))
+ {
+ count_type const& bc (c.get<count_type> ("column-count"));
- if (c.count (key))
- count_ += c.get<size_t> (key);
+ c_.total += bc.total;
+ c_.id += bc.id;
+ c_.inverse += bc.inverse;
+ c_.readonly += bc.readonly;
+ }
else
{
- size_t n (count_);
+ count_type t (c_);
object_members_base::traverse (c);
- c.set (key, count_ - n);
+
+ t.total = c_.total - t.total;
+ t.id = c_.id - t.id;
+ t.inverse = c_.inverse - t.inverse;
+ t.readonly = c_.readonly - t.readonly;
+
+ c.set ("column-count", t);
}
}
virtual void
traverse_simple (semantics::data_member& m)
{
- if (out_ || !context::inverse (m))
- count_++;
+ c_.total++;
+
+ if (m.count ("id"))
+ c_.id++;
+
+ if (context::inverse (m))
+ c_.inverse++;
}
private:
- bool out_;
- size_t count_;
+ count_type c_;
};
}
-size_t context::
-in_column_count (semantics::class_& c)
-{
- if (!c.count ("in-column-count"))
- {
- column_count_impl t (false);
- t.traverse (c);
- }
-
- return c.get<size_t> ("in-column-count");
-}
-
-size_t context::
-out_column_count (semantics::class_& c)
+context::column_count_type context::
+column_count (semantics::class_& c)
{
- if (!c.count ("out-column-count"))
+ if (!c.count ("column-count"))
{
- column_count_impl t (true);
+ column_count_impl t;
t.traverse (c);
}
- return c.get<size_t> ("out-column-count");
+ return c.get<column_count_type> ("column-count");
}
namespace
diff --git a/odb/context.hxx b/odb/context.hxx
index f91568a..ffafb43 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -216,7 +216,7 @@ public:
upcase (string const&);
public:
- semantics::type&
+ static semantics::type&
member_type (semantics::data_member& m, string const& key_prefix);
// Predicates.
@@ -234,12 +234,6 @@ public:
return t.count ("view");
}
- static bool
- transient (semantics::data_member& m)
- {
- return m.count ("transient");
- }
-
// Check whether the type is a wrapper. Return the wrapped type if
// it is a wrapper and NULL otherwise.
//
@@ -322,6 +316,24 @@ public:
return c.abstract () || c.count ("abstract");
}
+ static bool
+ transient (semantics::data_member& m)
+ {
+ return m.count ("transient");
+ }
+
+ static bool
+ id (semantics::data_member& m)
+ {
+ return m.count ("id");
+ }
+
+ bool
+ readonly (semantics::data_member& m)
+ {
+ return m.count ("readonly");
+ }
+
bool
null (semantics::data_member&);
@@ -412,11 +424,18 @@ public:
// Counts and other information.
//
public:
- static size_t
- in_column_count (semantics::class_&);
+ struct column_count_type
+ {
+ column_count_type (): total (0), id (0), inverse (0), readonly (0) {}
+
+ size_t total;
+ size_t id;
+ size_t inverse;
+ size_t readonly;
+ };
- static size_t
- out_column_count (semantics::class_&);
+ static column_count_type
+ column_count (semantics::class_&);
static semantics::data_member*
id_member (semantics::class_& c)
@@ -480,9 +499,9 @@ public:
}
static semantics::type&
- container_idt (semantics::type& c)
+ container_idt (semantics::data_member& m)
{
- return *c.get<semantics::type*> ("id-tree-type");
+ return member_type (m, "id");
}
static semantics::type&
@@ -578,7 +597,7 @@ private:
composite_ (semantics::class_&);
template <typename X>
- X
+ static X
indirect_value (semantics::context const& c, string const& key)
{
typedef X (*func) ();
diff --git a/odb/relational/context.hxx b/odb/relational/context.hxx
index 7bff5b1..cd2bce5 100644
--- a/odb/relational/context.hxx
+++ b/odb/relational/context.hxx
@@ -10,6 +10,14 @@
namespace relational
{
+ enum statement_kind
+ {
+ statement_select,
+ statement_insert,
+ statement_update,
+ statement_where // WHERE clause.
+ };
+
class context: public virtual ::context
{
public:
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index 0806042..4351db9 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -394,69 +394,79 @@ namespace relational
// Figure out column counts.
//
- size_t data_columns (1), cond_columns (1); // One for object id.
+ size_t data_columns, cond_columns;
- switch (ck)
+ if (!abst)
{
- case ck_ordered:
+ type& idt (container_idt (m));
+
+ if (class_* idc = composite_wrapper (idt))
+ data_columns = cond_columns = column_count (*idc).total;
+ else
+ data_columns = cond_columns = 1;
+
+ switch (ck)
{
- // Add one for the index.
- //
- if (ordered)
+ case ck_ordered:
{
- data_columns++;
-
- // Index is not currently used (see also bind()).
+ // Add one for the index.
//
- // cond_columns++;
+ if (ordered)
+ {
+ data_columns++;
+
+ // Index is not currently used (see also bind()).
+ //
+ // cond_columns++;
+ }
+ break;
}
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- // Add some for the key.
- //
- size_t n;
+ case ck_map:
+ case ck_multimap:
+ {
+ // Add some for the key.
+ //
+ size_t n;
- if (class_* kc = composite_wrapper (*kt))
- n = in_column_count (*kc);
- else
- n = 1;
+ if (class_* kc = composite_wrapper (*kt))
+ n = column_count (*kc).total;
+ else
+ n = 1;
- data_columns += n;
+ data_columns += n;
- // Key is not currently used (see also bind()).
- //
- // cond_columns += n;
+ // Key is not currently used (see also bind()).
+ //
+ // cond_columns += n;
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- // Not currently used (see also bind())
- //
- // Value is also a key.
- //
- //if (class_* vc = composite_wrapper (vt))
- // cond_columns += in_column_count (*vc);
- //else
- // cond_columns++;
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ // Not currently used (see also bind())
+ //
+ // Value is also a key.
+ //
+ //if (class_* vc = composite_wrapper (vt))
+ // cond_columns += column_count (*vc).total;
+ //else
+ // cond_columns++;
- break;
+ break;
+ }
}
- }
- if (class_* vc = composite_wrapper (vt))
- data_columns += in_column_count (*vc);
- else
- data_columns++;
+ if (class_* vc = composite_wrapper (vt))
+ data_columns += column_count (*vc).total;
+ else
+ data_columns++;
- // Store column counts for the source generator.
- //
- m.set ("cond-column-count", cond_columns);
- m.set ("data-column-count", data_columns);
+ // Store column counts for the source generator.
+ //
+ m.set ("cond-column-count", cond_columns);
+ m.set ("data-column-count", data_columns);
+ }
os << "// " << m.name () << endl
<< "//" << endl
@@ -913,6 +923,8 @@ namespace relational
bool auto_id (id ? id->count ("auto") : false);
bool base_id (id ? &id->scope () != &c : false); // Comes from base.
+ column_count_type const& cc (column_count (c));
+
os << "// " << c.name () << endl
<< "//" << endl;
@@ -1034,7 +1046,8 @@ namespace relational
// bind (image_type)
//
os << "static void" << endl
- << "bind (" << bind_vector << ", image_type&, bool);"
+ << "bind (" << bind_vector << ", image_type&, "
+ << db << "::statement_kind);"
<< endl;
// bind (id_image_type)
@@ -1049,7 +1062,8 @@ namespace relational
// init (image, object)
//
os << "static bool" << endl
- << "init (image_type&, const object_type&);"
+ << "init (image_type&, const object_type&, " <<
+ db << "::statement_kind);"
<< endl;
// init (object, image)
@@ -1104,18 +1118,23 @@ namespace relational
// column_count
//
- os << "static const std::size_t in_column_count = " <<
- in_column_count (c) << "UL;"
- << "static const std::size_t out_column_count = " <<
- out_column_count (c) << "UL;"
+ os << "static const std::size_t column_count = " << cc.total << "UL;"
+ << "static const std::size_t id_column_count = " << cc.id << "UL;"
+ << "static const std::size_t inverse_column_count = " <<
+ cc.inverse << "UL;"
+ << "static const std::size_t readonly_column_count = " <<
+ cc.readonly << "UL;"
<< endl;
// Statements.
//
os << "static const char persist_statement[];"
- << "static const char find_statement[];"
- << "static const char update_statement[];"
- << "static const char erase_statement[];";
+ << "static const char find_statement[];";
+
+ if (cc.total != cc.id + cc.inverse + cc.readonly)
+ os << "static const char update_statement[];";
+
+ os << "static const char erase_statement[];";
if (options.generate_query ())
{
@@ -1393,7 +1412,7 @@ namespace relational
// column_count
//
os << "static const std::size_t column_count = " <<
- out_column_count (c) << "UL;"
+ column_count (c).total << "UL;"
<< endl;
// Statements.
@@ -1475,13 +1494,15 @@ namespace relational
// bind (image_type)
//
os << "static void" << endl
- << "bind (" << bind_vector << ", image_type&);"
+ << "bind (" << bind_vector << ", image_type&, " <<
+ db << "::statement_kind);"
<< endl;
// init (image, value)
//
os << "static bool" << endl
- << "init (image_type&, const value_type&);"
+ << "init (image_type&, const value_type&, " <<
+ db << "::statement_kind);"
<< endl;
// init (value, image)
diff --git a/odb/relational/mysql/source.cxx b/odb/relational/mysql/source.cxx
index bea559e..103c301 100644
--- a/odb/relational/mysql/source.cxx
+++ b/odb/relational/mysql/source.cxx
@@ -77,7 +77,7 @@ namespace relational
// When we store a ENUM column in the MySQL database, if we bind
// an integer parameter, then it is treated as an index and if we
// bind a string, then it is treated as a enumerator. Everything
- // would have worked well if the same logic applied to the load
+ // would have worked well if the same logic applied to the select
// operation. That is, if we bind integer, then the database sends
// the index and if we bind string then the database sends the
// enumerator. Unfortunately, MySQL always sends the enumerator
@@ -112,7 +112,8 @@ namespace relational
// to value_traits.
//
- if (!out_ || column_sql_type (m, key_prefix).type != sql_type::ENUM)
+ if (sk_ != statement_select ||
+ column_sql_type (m, key_prefix).type != sql_type::ENUM)
{
base::column (m, key_prefix, table, column);
return;
@@ -197,7 +198,10 @@ namespace relational
<< "//" << endl;
if (inverse (mi.m, key_prefix_))
- os << "if (out)"
+ os << "if (sk == statement_select)"
+ << "{";
+ else if (id (mi.m) || readonly (mi.m))
+ os << "if (sk != statement_update)"
<< "{";
}
@@ -210,11 +214,42 @@ namespace relational
if (var_override_.empty ())
{
if (semantics::class_* c = composite (mi.t))
- os << "n += " << in_column_count (*c) << "UL;";
+ {
+ column_count_type const& cc (column_count (*c));
+
+ os << "n += " << cc.total << "UL";
+
+ // select = total
+ // insert = total - inverse
+ // update = total - inverse - readonly
+ //
+ if (cc.inverse != 0 || cc.readonly != 0)
+ {
+ os << " - (" << endl
+ << "sk == statement_select ? 0 : ";
+
+ if (cc.inverse != 0)
+ os << cc.inverse << "UL" << endl;
+
+ if (cc.readonly != 0)
+ {
+ if (cc.inverse != 0)
+ os << " + ";
+
+ os << "(" << endl
+ << "sk == statement_insert ? 0 : " <<
+ cc.readonly << "UL)";
+ }
+
+ os << ")";
+ }
+
+ os << ";";
+ }
else
os << "n++;";
- if (inverse (mi.m, key_prefix_))
+ if (inverse (mi.m, key_prefix_) || id (mi.m) || readonly (mi.m))
os << "}";
else
os << endl;
@@ -225,7 +260,7 @@ namespace relational
traverse_composite (member_info& mi)
{
os << "composite_value_traits< " << mi.fq_type () <<
- " >::bind (b + n, " << arg << "." << mi.var << "value);";
+ " >::bind (b + n, " << arg << "." << mi.var << "value, sk);";
}
virtual void
@@ -382,7 +417,7 @@ namespace relational
post (member_info& mi)
{
if (semantics::class_* c = composite (mi.t))
- index_ += in_column_count (*c);
+ index_ += column_count (*c).total;
else
index_++;
}
@@ -514,7 +549,7 @@ namespace relational
pre (member_info& mi)
{
// Ignore containers (they get their own table) and inverse
- // object pointers (they are not present in the 'in' binding).
+ // object pointers (they are not present in this binding).
//
if (container (mi.t) || inverse (mi.m, key_prefix_))
return false;
@@ -528,6 +563,11 @@ namespace relational
os << "// " << name << endl
<< "//" << endl;
+
+ if (id (mi.m) || readonly (mi.m))
+ // The block scope is added later, if necessary.
+ //
+ os << "if (sk == statement_insert)";
}
// If this is a wrapped composite value, then we need to
@@ -637,9 +677,12 @@ namespace relational
virtual void
traverse_composite (member_info& mi)
{
+ // Should be a single statement or a block.
+ //
os << "if (" << traits << "::init (" << endl
<< "i." << mi.var << "value," << endl
- << member << "))"
+ << member << "," << endl
+ << "sk))"
<< "{"
<< "grew = true;"
<< "}";
diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx
index e026214..dd3fe8b 100644
--- a/odb/relational/oracle/source.cxx
+++ b/odb/relational/oracle/source.cxx
@@ -91,7 +91,10 @@ namespace relational
<< "//" << endl;
if (inverse (mi.m, key_prefix_))
- os << "if (out)"
+ os << "if (sk == statement_select)"
+ << "{";
+ else if (id (mi.m) || readonly (mi.m))
+ os << "if (sk != statement_update)"
<< "{";
}
@@ -104,11 +107,43 @@ namespace relational
if (var_override_.empty ())
{
if (semantics::class_* c = composite (mi.t))
- os << "n += " << in_column_count (*c) << "UL;";
+
+ {
+ column_count_type const& cc (column_count (*c));
+
+ os << "n += " << cc.total << "UL";
+
+ // select = total
+ // insert = total - inverse
+ // update = total - inverse - readonly
+ //
+ if (cc.inverse != 0 || cc.readonly != 0)
+ {
+ os << " - (" << endl
+ << "sk == statement_select ? 0 : ";
+
+ if (cc.inverse != 0)
+ os << cc.inverse << "UL" << endl;
+
+ if (cc.readonly != 0)
+ {
+ if (cc.inverse != 0)
+ os << " + ";
+
+ os << "(" << endl
+ << "sk == statement_insert ? 0 : " <<
+ cc.readonly << "UL)";
+ }
+
+ os << ")";
+ }
+
+ os << ";";
+ }
else
os << "n++;";
- if (inverse (mi.m, key_prefix_))
+ if (inverse (mi.m, key_prefix_) || id (mi.m) || readonly (mi.m))
os << "}";
else
os << endl;
@@ -119,7 +154,7 @@ namespace relational
traverse_composite (member_info& mi)
{
os << "composite_value_traits< " << mi.fq_type () <<
- " >::bind (b + n, " << arg << "." << mi.var << "value);";
+ " >::bind (b + n, " << arg << "." << mi.var << "value, sk);";
}
virtual void
@@ -229,7 +264,7 @@ namespace relational
<< b << ".callback = &" << arg << "." << mi.var <<
"callback;"
<< b << ".context = &" << arg << "." << mi.var << "context;"
- << "if (out)" << endl
+ << "if (sk == statement_select)" << endl
<< b << ".buffer = &" << arg << "." << mi.var << "lob;"
<< "else" << endl
<< b << ".size = reinterpret_cast<ub2*> (&" << arg << "." <<
@@ -263,7 +298,7 @@ namespace relational
pre (member_info& mi)
{
// Ignore containers (they get their own table) and inverse
- // object pointers (they are not present in the 'in' binding).
+ // object pointers (they are not present in this binding).
//
if (container (mi.t) || inverse (mi.m, key_prefix_))
return false;
@@ -277,6 +312,11 @@ namespace relational
os << "// " << name << endl
<< "//" << endl;
+
+ if (id (mi.m) || readonly (mi.m))
+ // The block scope is added later, if necessary.
+ //
+ os << "if (sk == statement_insert)";
}
// If this is a wrapped composite value, then we need to
@@ -388,7 +428,8 @@ namespace relational
{
os << traits << "::init (" << endl
<< "i." << mi.var << "value," << endl
- << member << ");";
+ << member << "," << endl
+ << "sk);";
}
virtual void
diff --git a/odb/relational/pgsql/header.cxx b/odb/relational/pgsql/header.cxx
index 4043809..474b69c 100644
--- a/odb/relational/pgsql/header.cxx
+++ b/odb/relational/pgsql/header.cxx
@@ -26,12 +26,17 @@ namespace relational
if (abstract (c))
return;
+ column_count_type const& cc (column_count (c));
+
// Statement names.
//
os << "static const char persist_statement_name[];"
- << "static const char find_statement_name[];"
- << "static const char update_statement_name[];"
- << "static const char erase_statement_name[];";
+ << "static const char find_statement_name[];";
+
+ if (cc.total != cc.id + cc.inverse + cc.readonly)
+ os << "static const char update_statement_name[];";
+
+ os << "static const char erase_statement_name[];";
// Query statement name.
//
@@ -44,11 +49,13 @@ namespace relational
// Statement types.
//
os << "static const unsigned int persist_statement_types[];"
- << "static const unsigned int find_statement_types[];"
- << "static const unsigned int update_statement_types[];"
- << "static const unsigned int erase_statement_types[];"
- << endl;
+ << "static const unsigned int find_statement_types[];";
+
+ if (cc.total != cc.id + cc.inverse + cc.readonly)
+ os << "static const unsigned int update_statement_types[];";
+ os << "static const unsigned int erase_statement_types[];"
+ << endl;
}
virtual void
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
index c56e1e7..c5df9bd 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/relational/pgsql/source.cxx
@@ -104,16 +104,21 @@ namespace relational
struct statement_oids: object_columns_base, context
{
- statement_oids (bool out): out_ (out) {}
+ statement_oids (statement_kind sk): sk_ (sk) {}
virtual bool
traverse_column (semantics::data_member& m,
std::string const&,
bool first)
{
- // Ignore inverse object pointers if we are generating 'in' columns.
+ // Ignore certain columns depending on what kind statement we are
+ // generating. See object_columns in common source generator for
+ // details.
//
- if (!out_ && inverse (m) != 0)
+ if (inverse (m) && sk_ != statement_select)
+ return false;
+
+ if ((id (m) || readonly (m)) && sk_ == statement_update)
return false;
if (!first)
@@ -125,7 +130,7 @@ namespace relational
}
private:
- bool out_;
+ statement_kind sk_;
};
//
@@ -159,7 +164,10 @@ namespace relational
<< "//" << endl;
if (inverse (mi.m, key_prefix_))
- os << "if (out)"
+ os << "if (sk == statement_select)"
+ << "{";
+ else if (id (mi.m) || readonly (mi.m))
+ os << "if (sk != statement_update)"
<< "{";
}
@@ -172,11 +180,42 @@ namespace relational
if (var_override_.empty ())
{
if (semantics::class_* c = composite (mi.t))
- os << "n += " << in_column_count (*c) << "UL;";
+ {
+ column_count_type const& cc (column_count (*c));
+
+ os << "n += " << cc.total << "UL";
+
+ // select = total
+ // insert = total - inverse
+ // update = total - inverse - readonly
+ //
+ if (cc.inverse != 0 || cc.readonly != 0)
+ {
+ os << " - (" << endl
+ << "sk == statement_select ? 0 : ";
+
+ if (cc.inverse != 0)
+ os << cc.inverse << "UL" << endl;
+
+ if (cc.readonly != 0)
+ {
+ if (cc.inverse != 0)
+ os << " + ";
+
+ os << "(" << endl
+ << "sk == statement_insert ? 0 : " <<
+ cc.readonly << "UL)";
+ }
+
+ os << ")";
+ }
+
+ os << ";";
+ }
else
os << "n++;";
- if (inverse (mi.m, key_prefix_))
+ if (inverse (mi.m, key_prefix_) || id (mi.m) || readonly (mi.m))
os << "}";
else
os << endl;
@@ -187,7 +226,7 @@ namespace relational
traverse_composite (member_info& mi)
{
os << "composite_value_traits< " << mi.fq_type () <<
- " >::bind (b + n, " << arg << "." << mi.var << "value);";
+ " >::bind (b + n, " << arg << "." << mi.var << "value, sk);";
}
virtual void
@@ -309,7 +348,7 @@ namespace relational
post (member_info& mi)
{
if (semantics::class_* c = composite (mi.t))
- index_ += in_column_count (*c);
+ index_ += column_count (*c).total;
else
index_++;
}
@@ -415,7 +454,7 @@ namespace relational
pre (member_info& mi)
{
// Ignore containers (they get their own table) and inverse
- // object pointers (they are not present in the 'in' binding).
+ // object pointers (they are not present in this binding).
//
if (container (mi.t) || inverse (mi.m, key_prefix_))
return false;
@@ -429,6 +468,11 @@ namespace relational
os << "// " << name << endl
<< "//" << endl;
+
+ if (id (mi.m) || readonly (mi.m))
+ // The block scope is added later, if necessary.
+ //
+ os << "if (sk == statement_insert)";
}
// If this is a wrapped composite value, then we need to
@@ -538,9 +582,12 @@ namespace relational
virtual void
traverse_composite (member_info& mi)
{
+ // Should be a single statement or a block.
+ //
os << "if (" << traits << "::init (" << endl
<< "i." << mi.var << "value," << endl
- << member << "))"
+ << member << "," << endl
+ << "sk))"
<< "{"
<< "grew = true;"
<< "}";
@@ -887,21 +934,28 @@ namespace relational
if (abstract (c))
return;
+ column_count_type const& cc (column_count (c));
+
string const& n (c.fq_name ());
string traits ("access::object_traits< " + n + " >::");
string const& fn (flat_name (n));
string name_decl ("const char " + traits);
os << name_decl << endl
- << "persist_statement_name[] = " << strlit (fn + "_persist") << ";"
+ << "persist_statement_name[] = " << strlit (fn + "_persist") <<
+ ";"
<< endl
<< name_decl << endl
<< "find_statement_name[] = " << strlit (fn + "_find") << ";"
- << endl
- << name_decl << endl
- << "update_statement_name[] = " << strlit (fn + "_update") << ";"
- << endl
- << name_decl << endl
+ << endl;
+
+ if (cc.total != cc.id + cc.inverse + cc.readonly)
+ os << name_decl << endl
+ << "update_statement_name[] = " << strlit (fn + "_update") <<
+ ";"
+ << endl;
+
+ os << name_decl << endl
<< "erase_statement_name[] = " << strlit (fn + "_erase") << ";"
<< endl;
@@ -930,7 +984,7 @@ namespace relational
<< "persist_statement_types[] ="
<< "{";
- instance<statement_oids> st (false);
+ instance<statement_oids> st (statement_insert);
st->traverse (c);
os << "};";
@@ -943,7 +997,7 @@ namespace relational
<< "find_statement_types[] ="
<< "{";
- instance<statement_oids> st (true);
+ instance<statement_oids> st (statement_select);
st->traverse_column (*id_m, "", true);
os << "};";
@@ -951,14 +1005,21 @@ namespace relational
// update_statement_types.
//
+ if (cc.total != cc.id + cc.inverse + cc.readonly)
{
os << oid_decl << endl
<< "update_statement_types[] ="
<< "{";
- instance<statement_oids> st (false);
- st->traverse (c);
- st->traverse_column (*id_m, "", false);
+ {
+ instance<statement_oids> st (statement_update);
+ st->traverse (c);
+ }
+
+ {
+ instance<statement_oids> st (statement_where);
+ st->traverse_column (*id_m, "", false);
+ }
os << "};";
}
@@ -970,7 +1031,7 @@ namespace relational
<< "erase_statement_types[] ="
<< "{";
- instance<statement_oids> st (true);
+ instance<statement_oids> st (statement_where);
st->traverse_column (*id_m, "", true);
os << "};";
@@ -1130,7 +1191,7 @@ namespace relational
if (semantics::class_* ktc =
composite_wrapper (container_kt (t)))
{
- instance<statement_oids> st (false);
+ instance<statement_oids> st (statement_insert);
st->traverse (m, *ktc, "key", "key");
os << ",";
}
@@ -1148,7 +1209,7 @@ namespace relational
if (semantics::class_* vtc = composite_wrapper (vt))
{
- instance <statement_oids> st (false);
+ instance <statement_oids> st (statement_insert);
st->traverse (m, *vtc, "value", "value");
}
else
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index 99f6073..55f94f5 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -49,17 +49,17 @@ namespace relational
{
typedef object_columns base;
- object_columns (bool out,
+ object_columns (statement_kind sk,
bool last = true,
query_parameters* param = 0)
- : out_ (out), param_ (param), last_ (last)
+ : sk_ (sk), param_ (param), last_ (last)
{
}
object_columns (std::string const& table_qname,
- bool out,
+ statement_kind sk,
bool last = true)
- : out_ (out), param_ (0), table_name_ (table_qname), last_ (last)
+ : sk_ (sk), param_ (0), table_name_ (table_qname), last_ (last)
{
}
@@ -70,9 +70,15 @@ namespace relational
{
semantics::data_member* im (inverse (m));
- // Ignore inverse object pointers if we are generating 'in' columns.
+ // Ignore certain columns depending on what kind statement we are
+ // generating. Columns corresponding to the inverse members are
+ // only present in the select statements while the id and readonly
+ // columns are not present in the update statements.
//
- if (im != 0 && !out_)
+ if (im != 0 && sk_ != statement_select)
+ return false;
+
+ if ((id (m) || readonly (m)) && sk_ == statement_update)
return false;
if (!first)
@@ -155,7 +161,7 @@ namespace relational
}
protected:
- bool out_;
+ statement_kind sk_;
query_parameters* param_;
string line_;
string table_name_;
@@ -540,14 +546,39 @@ namespace relational
os << "// " << c.name () << " base" << endl
<< "//" << endl;
- if (obj)
- os << "object_traits< " << c.fq_name () <<
- " >::bind (b + n, i, out);";
- else
- os << "composite_value_traits< " << c.fq_name () <<
- " >::bind (b + n, i);";
+ os << (obj ? "object" : "composite_value") << "_traits< " <<
+ c.fq_name () << " >::bind (b + n, i, sk);";
+
+ column_count_type const& cc (column_count (c));
+
+ os << "n += " << cc.total << "UL";
+
+ // select = total
+ // insert = total - inverse
+ // update = total - inverse - id - readonly
+ //
+ if (cc.inverse != 0 || cc.id != 0 || cc.readonly != 0)
+ {
+ os << " - (" << endl
+ << "sk == statement_select ? 0 : ";
+
+ if (cc.inverse != 0)
+ os << cc.inverse << "UL" << endl;
+
+ if (cc.id != 0 || cc.readonly != 0)
+ {
+ if (cc.inverse != 0)
+ os << " + ";
+
+ os << "(" << endl
+ << "sk == statement_insert ? 0 : " <<
+ cc.id + cc.readonly << "UL)";
+ }
+
+ os << ")";
+ }
- os << "n += " << in_column_count (c) << "UL;"
+ os << ";"
<< endl;
}
};
@@ -602,7 +633,7 @@ namespace relational
<< "grew = true;"
<< endl;
- index_ += in_column_count (c);
+ index_ += column_count (c).total;
}
protected:
@@ -655,7 +686,7 @@ namespace relational
os << "// " << c.name () << " base" << endl
<< "//" << endl
<< "if (" << (obj ? "object" : "composite_value") << "_traits< " <<
- c.fq_name () << " >::init (i, o))" << endl
+ c.fq_name () << " >::init (i, o, sk))" << endl
<< "grew = true;"
<< endl;
}
@@ -905,7 +936,7 @@ namespace relational
{
if (ordered)
{
- instance<object_columns> t (table, false, false);
+ instance<object_columns> t (table, statement_select, false);
string const& col (column_qname (m, "index", "index"));
t->column (m, "index", table, col);
t->flush ();
@@ -915,7 +946,7 @@ namespace relational
case ck_map:
case ck_multimap:
{
- instance<object_columns> t (table, false, false);
+ instance<object_columns> t (table, statement_select, false);
if (semantics::class_* ckt = composite_wrapper (*kt))
t->traverse (m, *ckt, "key", "key");
@@ -934,7 +965,7 @@ namespace relational
}
}
- instance<object_columns> t (table, false);
+ instance<object_columns> t (table, statement_select);
if (semantics::class_* cvt = composite_wrapper (vt))
t->traverse (m, *cvt, "value", "value");
@@ -982,7 +1013,7 @@ namespace relational
{
if (ordered)
{
- instance<object_columns> t (false, false);
+ instance<object_columns> t (statement_insert, false);
t->column (m, "index", "", column_qname (m, "index", "index"));
t->flush ();
}
@@ -991,7 +1022,7 @@ namespace relational
case ck_map:
case ck_multimap:
{
- instance<object_columns> t (false, false);
+ instance<object_columns> t (statement_insert, false);
if (semantics::class_* ckt = composite_wrapper (*kt))
t->traverse (m, *ckt, "key", "key");
@@ -1009,7 +1040,7 @@ namespace relational
}
}
- instance<object_columns> t (false);
+ instance<object_columns> t (statement_insert);
if (semantics::class_* cvt = composite_wrapper (vt))
t->traverse (m, *cvt, "value", "value");
@@ -1089,6 +1120,8 @@ namespace relational
// Index/key is currently not used (see also cond_column_count).
//
#if 0
+ // Would need statement_kind if this is enabled.
+ //
switch (ck)
{
case ck_ordered:
@@ -1135,6 +1168,15 @@ namespace relational
<< "std::size_t id_size," << endl
<< "data_image_type& d)"
<< "{"
+ << "using namespace " << db << ";"
+ << endl
+ // In the case of containers, insert and select column sets are
+ // the same since we can't have inverse members as container
+ // elements.
+ //
+ << "statement_kind sk (statement_select);"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
+ << endl
<< "size_t n (0);"
<< endl;
@@ -1170,7 +1212,7 @@ namespace relational
bm->traverse (m);
if (semantics::class_* c = composite_wrapper (*kt))
- os << "n += " << in_column_count (*c) << "UL;"
+ os << "n += " << column_count (*c).total << "UL;"
<< endl;
else
os << "n++;"
@@ -1263,11 +1305,36 @@ namespace relational
"const value_type& v)";
else
os << "init (data_image_type& i, const value_type& v)";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "init (data_image_type& i, const key_type& k, " <<
+ "const value_type& v)";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "init (data_image_type& i, const value_type& v)";
+ break;
+ }
+ }
- os << "{"
- << "bool grew (false);"
- << endl;
+ os << "{"
+ << "using namespace " << db << ";"
+ << endl
+ << "statement_kind sk (statement_insert);"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
+ << endl
+ << "bool grew (false);"
+ << endl;
+ switch (ck)
+ {
+ case ck_ordered:
+ {
if (ordered)
{
os << "// index" << endl
@@ -1277,18 +1344,12 @@ namespace relational
"index_", "j", *it, "index_type", "index");
im->traverse (m);
}
-
break;
}
case ck_map:
case ck_multimap:
{
- os << "init (data_image_type& i, const key_type& k, " <<
- "const value_type& v)"
- << "{"
- << "bool grew (false);"
- << endl
- << "// key" << endl
+ os << "// key" << endl
<< "//" << endl;
instance<init_image_member> im (
@@ -1300,11 +1361,6 @@ namespace relational
case ck_set:
case ck_multiset:
{
- os << "init (data_image_type& i, const value_type& v)"
- << "{"
- << "bool grew (false);"
- << endl;
-
break;
}
}
@@ -2124,6 +2180,8 @@ namespace relational
grow_id = id ? context::grow (*id) : false;
}
+ column_count_type const& cc (column_count (c));
+
os << "// " << c.name () << endl
<< "//" << endl
<< endl;
@@ -2199,9 +2257,12 @@ namespace relational
// bind (image_type)
//
os << "void " << traits << "::" << endl
- << "bind (" << bind_vector << " b, image_type& i, bool out)"
+ << "bind (" << bind_vector << " b, image_type& i, " <<
+ db << "::statement_kind sk)"
<< "{"
- << "ODB_POTENTIALLY_UNUSED (out);"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
+ << endl
+ << "using namespace " << db << ";"
<< endl
<< "std::size_t n (0);"
<< endl;
@@ -2226,10 +2287,14 @@ namespace relational
// init (image, object)
//
os << "bool " << traits << "::" << endl
- << "init (image_type& i, const object_type& o)"
+ << "init (image_type& i, const object_type& o, " <<
+ db << "::statement_kind sk)"
<< "{"
<< "ODB_POTENTIALLY_UNUSED (i);"
<< "ODB_POTENTIALLY_UNUSED (o);"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
+ << endl
+ << "using namespace " << db << ";"
<< endl
<< "bool grew (false);"
<< endl;
@@ -2321,7 +2386,7 @@ namespace relational
"=" << endl
<< strlit ("INSERT INTO " + table_qname(c) + " (") << endl;
- instance<object_columns> ct (false);
+ instance<object_columns> ct (statement_insert);
ct->traverse (c);
string values;
@@ -2343,7 +2408,7 @@ namespace relational
os << "const char " << traits << "::find_statement[] =" << endl
<< strlit ("SELECT ") << endl;
- instance<object_columns> t (table, true);
+ instance<object_columns> t (table, statement_select);
t->traverse (c);
os << strlit (" FROM " + table) << endl;
@@ -2361,13 +2426,14 @@ namespace relational
// update_statement
//
+ if (cc.total != cc.id + cc.inverse + cc.readonly)
{
os << "const char " << traits << "::update_statement[] " <<
"=" << endl
<< strlit ("UPDATE " + table + " SET ") << endl;
instance<query_parameters> qp;
- instance<object_columns> t (false, true, qp.get ());
+ instance<object_columns> t (statement_update, true, qp.get ());
t->traverse (c);
os << strlit (" WHERE " + id_col + "=" + qp->next ()) << ";"
@@ -2396,7 +2462,7 @@ namespace relational
<< strlit ("SELECT ") << endl;
{
- instance<object_columns> oc (table, true);
+ instance<object_columns> oc (table, statement_select);
oc->traverse (c);
}
@@ -2441,9 +2507,9 @@ namespace relational
<< "object_statements< object_type >& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());"
<< "image_type& im (sts.image ());"
- << "binding& imb (sts.in_image_binding ());"
+ << "binding& imb (sts.insert_image_binding ());"
<< endl
- << "if (init (im, obj))" << endl
+ << "if (init (im, obj, statement_insert))" << endl
<< "im.version++;"
<< endl;
@@ -2455,10 +2521,11 @@ namespace relational
os << endl;
}
- os << "if (im.version != sts.in_image_version () || imb.version == 0)"
+ os << "if (im.version != sts.insert_image_version () || " <<
+ "imb.version == 0)"
<< "{"
- << "bind (imb.bind, im, false);"
- << "sts.in_image_version (im.version);"
+ << "bind (imb.bind, im, statement_insert);"
+ << "sts.insert_image_version (im.version);"
<< "imb.version++;"
<< "}"
<< "insert_statement& st (sts.persist_statement ());"
@@ -2504,42 +2571,59 @@ namespace relational
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl;
- // Initialize id image.
- //
- os << "id_image_type& i (sts.id_image ());"
- << "init (i, obj." << id->name () << ");"
- << endl;
+ if (cc.total != cc.id + cc.inverse + cc.readonly)
+ {
+ // Initialize id image.
+ //
+ os << "id_image_type& i (sts.id_image ());"
+ << "init (i, obj." << id->name () << ");"
+ << endl;
- os << "binding& idb (sts.id_image_binding ());"
- << "if (i.version != sts.id_image_version () || idb.version == 0)"
- << "{"
- << "bind (idb.bind, i);"
- << "sts.id_image_version (i.version);"
- << "idb.version++;"
- << "}";
+ os << "binding& idb (sts.id_image_binding ());"
+ << "if (i.version != sts.id_image_version () || idb.version == 0)"
+ << "{"
+ << "bind (idb.bind, i);"
+ << "sts.id_image_version (i.version);"
+ << "idb.version++;"
+ << "}";
- // Initialize data image.
- //
- os << "image_type& im (sts.image ());"
- << "binding& imb (sts.in_image_binding ());"
- << endl
- << "if (init (im, obj))" << endl
- << "im.version++;"
- << endl
- << "if (im.version != sts.in_image_version () || imb.version == 0)"
- << "{"
- << "bind (imb.bind, im, false);"
- << "sts.in_image_version (im.version);"
- << "imb.version++;"
- << "}"
- << "sts.update_statement ().execute ();";
+ // Initialize data image.
+ //
+ os << "image_type& im (sts.image ());"
+ << "binding& imb (sts.update_image_binding ());"
+ << endl
+ << "if (init (im, obj, statement_update))" << endl
+ << "im.version++;"
+ << endl
+ << "if (im.version != sts.update_image_version () || " <<
+ "imb.version == 0)"
+ << "{"
+ << "bind (imb.bind, im, statement_update);"
+ << "sts.update_image_version (im.version);"
+ << "imb.version++;"
+ << "}"
+ << "sts.update_statement ().execute ();";
+ }
+ else
+ {
+ // We don't have any columns to update. Note that we still have
+ // to make sure this object exists in the database. For that we
+ // will run the SELECT query using the find_() function.
+ //
+ os << "if (!find_ (sts, obj." << id->name () << "))" << endl
+ << "throw object_not_persistent ();";
if (straight_containers)
- {
- os << endl;
- instance<container_calls> t (container_calls::update_call);
- t->traverse (c);
- }
+ os << endl
+ << "binding& idb (sts.id_image_binding ());";
+ }
+
+ if (straight_containers)
+ {
+ os << endl;
+ instance<container_calls> t (container_calls::update_call);
+ t->traverse (c);
+ }
os << "}";
@@ -2702,12 +2786,13 @@ namespace relational
// Rebind data image.
//
os << "image_type& im (sts.image ());"
- << "binding& imb (sts.out_image_binding ());"
+ << "binding& imb (sts.select_image_binding ());"
<< endl
- << "if (im.version != sts.out_image_version () || imb.version == 0)"
+ << "if (im.version != sts.select_image_version () || " <<
+ "imb.version == 0)"
<< "{"
- << "bind (imb.bind, im, true);"
- << "sts.out_image_version (im.version);"
+ << "bind (imb.bind, im, statement_select);"
+ << "sts.select_image_version (im.version);"
<< "imb.version++;"
<< "}"
<< "select_statement& st (sts.find_statement ());"
@@ -2718,13 +2803,13 @@ namespace relational
os << endl
<< "if (r == select_statement::truncated)"
<< "{"
- << "if (grow (im, sts.out_image_truncated ()))" << endl
+ << "if (grow (im, sts.select_image_truncated ()))" << endl
<< "im.version++;"
<< endl
- << "if (im.version != sts.out_image_version ())"
+ << "if (im.version != sts.select_image_version ())"
<< "{"
- << "bind (imb.bind, im, true);"
- << "sts.out_image_version (im.version);"
+ << "bind (imb.bind, im, statement_select);"
+ << "sts.select_image_version (im.version);"
<< "imb.version++;"
<< "st.refetch ();"
<< "}"
@@ -2768,12 +2853,13 @@ namespace relational
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl
<< "image_type& im (sts.image ());"
- << "binding& imb (sts.out_image_binding ());"
+ << "binding& imb (sts.select_image_binding ());"
<< endl
- << "if (im.version != sts.out_image_version () || imb.version == 0)"
+ << "if (im.version != sts.select_image_version () || " <<
+ "imb.version == 0)"
<< "{"
- << "bind (imb.bind, im, true);"
- << "sts.out_image_version (im.version);"
+ << "bind (imb.bind, im, statement_select);"
+ << "sts.select_image_version (im.version);"
<< "imb.version++;"
<< "}"
<< "shared_ptr<select_statement> st (" << endl
@@ -3077,8 +3163,10 @@ namespace relational
os << "void " << traits << "::" << endl
<< "bind (" << bind_vector << " b, image_type& i)"
<< "{"
- << "bool out (true);" //@@ Try to get rid of this.
- << "ODB_POTENTIALLY_UNUSED (out);"
+ << "using namespace " << db << ";"
+ << endl
+ << db << "::statement_kind sk (statement_select);"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
<< endl
<< "std::size_t n (0);"
<< endl;
@@ -3765,10 +3853,14 @@ namespace relational
// bind (image_type)
//
os << "void " << traits << "::" << endl
- << "bind (" << bind_vector << " b, image_type& i)"
+ << "bind (" << bind_vector << " b, image_type& i, " <<
+ db << "::statement_kind sk)"
<< "{"
<< "ODB_POTENTIALLY_UNUSED (b);"
<< "ODB_POTENTIALLY_UNUSED (i);"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
+ << endl
+ << "using namespace " << db << ";"
<< endl
<< "std::size_t n (0);"
<< "ODB_POTENTIALLY_UNUSED (n);"
@@ -3782,10 +3874,14 @@ namespace relational
// init (image, value)
//
os << "bool " << traits << "::" << endl
- << "init (image_type& i, const value_type& o)"
+ << "init (image_type& i, const value_type& o, " <<
+ db << "::statement_kind sk)"
<< "{"
<< "ODB_POTENTIALLY_UNUSED (i);"
<< "ODB_POTENTIALLY_UNUSED (o);"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
+ << endl
+ << "using namespace " << db << ";"
<< endl
<< "bool grew (false);"
<< endl;
@@ -3867,7 +3963,8 @@ namespace relational
os << endl;
- os << "#include <odb/" << db << "/traits.hxx>" << endl
+ os << "#include <odb/" << db << "/binding.hxx>" << endl
+ << "#include <odb/" << db << "/traits.hxx>" << endl
<< "#include <odb/" << db << "/database.hxx>" << endl
<< "#include <odb/" << db << "/transaction.hxx>" << endl
<< "#include <odb/" << db << "/connection.hxx>" << endl
diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx
index 8b02e6c..89173dd 100644
--- a/odb/relational/sqlite/source.cxx
+++ b/odb/relational/sqlite/source.cxx
@@ -49,7 +49,10 @@ namespace relational
<< "//" << endl;
if (inverse (mi.m, key_prefix_))
- os << "if (out)"
+ os << "if (sk == statement_select)"
+ << "{";
+ else if (id (mi.m) || readonly (mi.m))
+ os << "if (sk != statement_update)"
<< "{";
}
@@ -62,11 +65,42 @@ namespace relational
if (var_override_.empty ())
{
if (semantics::class_* c = composite (mi.t))
- os << "n += " << in_column_count (*c) << "UL;";
+ {
+ column_count_type const& cc (column_count (*c));
+
+ os << "n += " << cc.total << "UL";
+
+ // select = total
+ // insert = total - inverse
+ // update = total - inverse - readonly
+ //
+ if (cc.inverse != 0 || cc.readonly != 0)
+ {
+ os << " - (" << endl
+ << "sk == statement_select ? 0 : ";
+
+ if (cc.inverse != 0)
+ os << cc.inverse << "UL" << endl;
+
+ if (cc.readonly != 0)
+ {
+ if (cc.inverse != 0)
+ os << " + ";
+
+ os << "(" << endl
+ << "sk == statement_insert ? 0 : " <<
+ cc.readonly << "UL)";
+ }
+
+ os << ")";
+ }
+
+ os << ";";
+ }
else
os << "n++;";
- if (inverse (mi.m, key_prefix_))
+ if (inverse (mi.m, key_prefix_) || id (mi.m) || readonly (mi.m))
os << "}";
else
os << endl;
@@ -77,7 +111,7 @@ namespace relational
traverse_composite (member_info& mi)
{
os << "composite_value_traits< " << mi.fq_type () <<
- " >::bind (b + n, " << arg << "." << mi.var << "value);";
+ " >::bind (b + n, " << arg << "." << mi.var << "value, sk);";
}
virtual void
@@ -158,7 +192,7 @@ namespace relational
post (member_info& mi)
{
if (semantics::class_* c = composite (mi.t))
- index_ += in_column_count (*c);
+ index_ += column_count (*c).total;
else
index_++;
}
@@ -223,7 +257,7 @@ namespace relational
pre (member_info& mi)
{
// Ignore containers (they get their own table) and inverse
- // object pointers (they are not present in the 'in' binding).
+ // object pointers (they are not present in this binding).
//
if (container (mi.t) || inverse (mi.m, key_prefix_))
return false;
@@ -237,6 +271,11 @@ namespace relational
os << "// " << name << endl
<< "//" << endl;
+
+ if (id (mi.m) || readonly (mi.m))
+ // The block scope is added later, if necessary.
+ //
+ os << "if (sk == statement_insert)";
}
// If this is a wrapped composite value, then we need to
@@ -345,9 +384,12 @@ namespace relational
virtual void
traverse_composite (member_info& mi)
{
+ // Should be a single statement or a block.
+ //
os << "if (" << traits << "::init (" << endl
<< "i." << mi.var << "value," << endl
- << member << "))"
+ << member << "," << endl
+ << "sk))"
<< "{"
<< "grew = true;"
<< "}";