aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/context.cxx19
-rw-r--r--odb/context.hxx7
-rw-r--r--odb/processor.cxx85
-rw-r--r--odb/relational/header.hxx280
-rw-r--r--odb/relational/inline.hxx3
-rw-r--r--odb/relational/mssql/source.cxx2
-rw-r--r--odb/relational/oracle/source.cxx2
-rw-r--r--odb/relational/pgsql/header.cxx28
-rw-r--r--odb/relational/pgsql/source.cxx127
-rw-r--r--odb/relational/source.cxx301
-rw-r--r--odb/relational/source.hxx634
11 files changed, 1072 insertions, 416 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
index 515e9a8..e419aba 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -2274,7 +2274,8 @@ namespace
unsigned short f (flags_ & (context::test_container |
context::test_straight_container |
context::test_inverse_container |
- context::test_readonly_container));
+ context::test_readonly_container |
+ context::test_smart_container));
if (context::is_a (member_path_,
member_scope_,
@@ -2319,22 +2320,28 @@ is_a (data_member_path const& mp,
if (f & test_lazy_pointer)
r = r || (object_pointer (t) && lazy_pointer (t));
+ semantics::type* c;
if ((f & (test_container |
test_straight_container |
test_inverse_container |
- test_readonly_container)) != 0)
+ test_readonly_container |
+ test_smart_container)) != 0 &&
+ (c = container (m)) != 0)
{
if (f & test_container)
- r = r || container (m);
+ r = r || true;
if (f & test_straight_container)
- r = r || (container(m) && !inverse (m, kp));
+ r = r || !inverse (m, kp);
if (f & test_inverse_container)
- r = r || (container (m) && inverse (m, kp));
+ r = r || inverse (m, kp);
if (f & test_readonly_container)
- r = r || (container (m) && readonly (mp, ms));
+ r = r || readonly (mp, ms);
+
+ if (f & test_smart_container)
+ r = r || (!inverse (m, kp) && !unordered (m) && container_smart (*c));
}
return r;
diff --git a/odb/context.hxx b/odb/context.hxx
index aa604e4..db8d217 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -866,6 +866,12 @@ public:
return c.get<container_kind_type> ("container-kind");
}
+ static bool
+ container_smart (semantics::type& c)
+ {
+ return c.get<bool> ("container-smart");
+ }
+
static semantics::type&
container_idt (semantics::data_member& m)
{
@@ -913,6 +919,7 @@ public:
static unsigned short const test_straight_container = 0x10;
static unsigned short const test_inverse_container = 0x20;
static unsigned short const test_readonly_container = 0x40;
+ static unsigned short const test_smart_container = 0x80;
// By default the test goes into bases for non-polymorphic
// hierarchies and doesn't go for polymorphic. The following
diff --git a/odb/processor.cxx b/odb/processor.cxx
index c290cca..2e94bc6 100644
--- a/odb/processor.cxx
+++ b/odb/processor.cxx
@@ -1106,6 +1106,7 @@ namespace
//
container_kind_type ck;
+ bool smart;
semantics::type* vt (0);
semantics::type* it (0);
semantics::type* kt (0);
@@ -1117,6 +1118,7 @@ namespace
if (t.count ("container-kind"))
{
ck = t.get<container_kind_type> ("container-kind");
+ smart = t.get<bool> ("container-smart");
vt = t.get<semantics::type*> ("value-tree-type");
vh = t.get<semantics::names*> ("value-tree-hint");
@@ -1151,22 +1153,21 @@ namespace
//
try
{
- tree kind (
+ tree decl (
lookup_qualified_name (
inst, get_identifier ("kind"), false, false));
- if (kind == error_mark_node || TREE_CODE (kind) != VAR_DECL)
+ if (decl == error_mark_node || TREE_CODE (decl) != VAR_DECL)
throw operation_failed ();
-
// Instantiate this decalaration so that we can get its value.
//
- if (DECL_TEMPLATE_INSTANTIATION (kind) &&
- !DECL_TEMPLATE_INSTANTIATED (kind) &&
- !DECL_EXPLICIT_INSTANTIATION (kind))
- instantiate_decl (kind, false, false);
+ if (DECL_TEMPLATE_INSTANTIATION (decl) &&
+ !DECL_TEMPLATE_INSTANTIATED (decl) &&
+ !DECL_EXPLICIT_INSTANTIATION (decl))
+ instantiate_decl (decl, false, false);
- tree init (DECL_INITIAL (kind));
+ tree init (DECL_INITIAL (decl));
if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST)
throw operation_failed ();
@@ -1197,6 +1198,63 @@ namespace
t.set ("container-kind", ck);
+ // See if it is a smart container.
+ //
+ try
+ {
+ tree decl (
+ lookup_qualified_name (
+ inst, get_identifier ("smart"), false, false));
+
+ if (decl == error_mark_node || TREE_CODE (decl) != VAR_DECL)
+ throw operation_failed ();
+
+ // Instantiate this decalaration so that we can get its value.
+ //
+ if (DECL_TEMPLATE_INSTANTIATION (decl) &&
+ !DECL_TEMPLATE_INSTANTIATED (decl) &&
+ !DECL_EXPLICIT_INSTANTIATION (decl))
+ instantiate_decl (decl, false, false);
+
+ tree init (DECL_INITIAL (decl));
+
+ if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST)
+ throw operation_failed ();
+
+ unsigned long long e;
+
+ {
+ HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init));
+ HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init));
+
+ unsigned long long l (hwl);
+ unsigned long long h (hwh);
+ unsigned short width (HOST_BITS_PER_WIDE_INT);
+
+ e = (h << width) + l;
+ }
+
+ smart = static_cast<bool> (e);
+ }
+ catch (operation_failed const&)
+ {
+ os << f << ":" << l << ":" << c << ": error: "
+ << "container_traits specialization does not define the "
+ << "'smart' constant" << endl;
+ throw;
+ }
+
+ // For now we only support ordered smart containers.
+ //
+ if (smart && ck != ck_ordered)
+ {
+ os << f << ":" << l << ":" << c << ": error: only ordered smart " <<
+ "containers are currently supported" << endl;
+ throw operation_failed ();
+ }
+
+ t.set ("container-smart", smart);
+
// Mark id column as not null.
//
t.set ("id-not-null", true);
@@ -1370,6 +1428,16 @@ namespace
if (ck == ck_ordered && m.count ("value-inverse"))
m.set ("unordered", true);
+ // Issue an error if we have a non-inverse smart unordered container.
+ //
+ if (smart && ck == ck_ordered && unordered (m) &&
+ !m.count ("value-inverse"))
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: smart ordered container cannot be unordered" << endl;
+ throw operation_failed ();
+ }
+
// Issue an error if we have a null column in a set container.
// This can only happen if the value is declared as null in
// the member.
@@ -1378,7 +1446,6 @@ namespace
{
os << m.file () << ":" << m.line () << ":" << m.column () << ":"
<< " error: set container cannot contain null values" << endl;
-
throw operation_failed ();
}
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index 3e0480f..cc36761 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -168,12 +168,12 @@ namespace relational
}
virtual void
- container_public_extra_pre (semantics::data_member&)
+ container_public_extra_pre (semantics::data_member&, semantics::type&)
{
}
virtual void
- container_public_extra_post (semantics::data_member&)
+ container_public_extra_post (semantics::data_member&, semantics::type&)
{
}
@@ -233,11 +233,15 @@ namespace relational
}
}
+ bool smart (!inverse &&
+ (ck != ck_ordered || ordered) &&
+ container_smart (c));
+
string name (flat_prefix_ + public_name (m) + "_traits");
// Figure out column counts.
//
- size_t id_columns, data_columns, cond_columns;
+ size_t id_columns, value_columns, data_columns, cond_columns;
if (!reuse_abst)
{
@@ -260,9 +264,8 @@ namespace relational
{
data_columns++;
- // Index is not currently used (see also bind()).
- //
- // cond_columns++;
+ if (smart)
+ cond_columns++;
}
break;
}
@@ -313,14 +316,17 @@ namespace relational
semantics::type& t (ptr == 0 ? vt : utype (*id_member (*ptr)));
if (class_* comp = composite_wrapper (t))
- data_columns += column_count (*comp).total;
+ value_columns = column_count (*comp).total;
else
- data_columns++;
+ value_columns = 1;
+
+ data_columns += value_columns;
}
// Store column counts for the source generator.
//
m.set ("id-column-count", id_columns);
+ m.set ("value-column-count", value_columns);
m.set ("cond-column-count", cond_columns);
m.set ("data-column-count", data_columns);
}
@@ -344,31 +350,40 @@ namespace relational
os << "{";
- container_public_extra_pre (m);
+ container_public_extra_pre (m, c);
if (!reuse_abst)
{
// column_count
//
os << "static const std::size_t id_column_count = " <<
- id_columns << "UL;"
- << "static const std::size_t cond_column_count = " <<
- cond_columns << "UL;"
- << "static const std::size_t data_column_count = " <<
+ id_columns << "UL;";
+
+ if (smart)
+ os << "static const std::size_t value_column_count = " <<
+ value_columns << "UL;"
+ << "static const std::size_t cond_column_count = " <<
+ cond_columns << "UL;";
+
+ os << "static const std::size_t data_column_count = " <<
data_columns << "UL;"
<< endl;
// Statements.
//
- os << "static const char insert_one_statement[];"
- << "static const char select_all_statement[];"
- << "static const char delete_all_statement[];"
+ os << "static const char insert_statement[];"
+ << "static const char select_statement[];";
+
+ if (smart)
+ os << "static const char update_statement[];";
+
+ os << "static const char delete_statement[];"
<< endl;
}
if (base)
{
- container_public_extra_post (m);
+ container_public_extra_post (m, c);
os << "};";
return;
@@ -437,8 +452,8 @@ namespace relational
{
case ck_ordered:
{
- os << "typedef ordered_functions<index_type, value_type> " <<
- "functions_type;";
+ os << "typedef " << (smart ? "smart_" : "") <<
+ "ordered_functions<index_type, value_type> functions_type;";
break;
}
case ck_map:
@@ -456,50 +471,56 @@ namespace relational
}
}
- os << "typedef " << db << "::container_statements< " << name <<
- " > statements_type;"
+ os << "typedef " << db << "::" << (smart ? "smart_" : "")
+ << "container_statements< " << name << " > statements_type;"
<< endl;
- // cond_image_type (object id is taken from the object image)
+ // cond_image_type (object id is taken from the object image).
//
- os << "struct cond_image_type"
- << "{";
-
- switch (ck)
+ // For dumb containers we use the id binding directly.
+ //
+ if (smart)
{
- case ck_ordered:
+ os << "struct cond_image_type"
+ << "{";
+
+ switch (ck)
{
- if (ordered)
+ case ck_ordered:
{
- os << "// index" << endl
+ if (ordered)
+ {
+ os << "// index" << endl
+ << "//" << endl;
+ instance<image_member> im (
+ "index_", *it, "index_type", "index");
+ im->traverse (m);
+ }
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "// key" << endl
<< "//" << endl;
- instance<image_member> im ("index_", *it, "index_type", "index");
+ instance<image_member> im ("key_", *kt, "key_type", "key");
im->traverse (m);
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "// value" << endl
+ << "//" << endl;
+ instance<image_member> im ("value_", vt, "value_type", "value");
+ im->traverse (m);
+ break;
}
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- os << "// key" << endl
- << "//" << endl;
- instance<image_member> im ("key_", *kt, "key_type", "key");
- im->traverse (m);
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- os << "// value" << endl
- << "//" << endl;
- instance<image_member> im ("value_", vt, "value_type", "value");
- im->traverse (m);
- break;
}
- }
- os << "std::size_t version;"
- << "};";
+ os << "std::size_t version;"
+ << "};";
+ }
// data_image_type (object id is taken from the object image)
//
@@ -545,12 +566,13 @@ namespace relational
// bind (cond_image)
//
- os << "static void" << endl
- << "bind (" << bind_vector << "," << endl
- << "const " << bind_vector << " id," << endl
- << "std::size_t id_size," << endl
- << "cond_image_type&);"
- << endl;
+ if (smart)
+ os << "static void" << endl
+ << "bind (" << bind_vector << "," << endl
+ << "const " << bind_vector << " id," << endl
+ << "std::size_t id_size," << endl
+ << "cond_image_type&);"
+ << endl;
// bind (data_image)
//
@@ -561,6 +583,17 @@ namespace relational
<< "data_image_type&);"
<< endl;
+ // bind (cond_image, data_image) (update)
+ //
+ if (smart)
+ os << "static void" << endl
+ << "bind (" << bind_vector << "," << endl
+ << "const " << bind_vector << " id," << endl
+ << "std::size_t id_size," << endl
+ << "cond_image_type&," << endl
+ << "data_image_type&);"
+ << endl;
+
// grow ()
//
if (generate_grow)
@@ -581,7 +614,7 @@ namespace relational
case ck_ordered:
{
if (ordered)
- os << "init (data_image_type&, index_type, const value_type&);";
+ os << "init (data_image_type&, index_type*, const value_type&);";
else
os << "init (data_image_type&, const value_type&);";
break;
@@ -589,7 +622,7 @@ namespace relational
case ck_map:
case ck_multimap:
{
- os << "init (data_image_type&, const key_type&, const value_type&);";
+ os << "init (data_image_type&, const key_type*, const value_type&);";
break;
}
case ck_set:
@@ -603,6 +636,36 @@ namespace relational
os << endl;
}
+ // init (cond_image)
+ //
+ if (smart)
+ {
+ os << "static void" << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "init (cond_image_type&, index_type);";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ // os << "init (data_image_type&, const key_type&);";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ // os << "init (data_image_type&, const value_type&);";
+ break;
+ }
+ }
+
+ os << endl;
+ }
+
// init (data)
//
os << "static void" << endl;
@@ -634,7 +697,7 @@ namespace relational
os << "const data_image_type&, database*);"
<< endl;
- // insert_one
+ // insert
//
os << "static void" << endl;
@@ -642,26 +705,26 @@ namespace relational
{
case ck_ordered:
{
- os << "insert_one (index_type, const value_type&, void*);";
+ os << "insert (index_type, const value_type&, void*);";
break;
}
case ck_map:
case ck_multimap:
{
- os << "insert_one (const key_type&, const value_type&, void*);";
+ os << "insert (const key_type&, const value_type&, void*);";
break;
}
case ck_set:
case ck_multiset:
{
- os << "insert_one (const value_type&, void*);";
+ os << "insert (const value_type&, void*);";
break;
}
}
os << endl;
- // load_all
+ // select
//
os << "static bool" << endl;
@@ -669,65 +732,120 @@ namespace relational
{
case ck_ordered:
{
- os << "load_all (index_type&, value_type&, void*);";
+ os << "select (index_type&, value_type&, void*);";
break;
}
case ck_map:
case ck_multimap:
{
- os << "load_all (key_type&, value_type&, void*);";
+ os << "select (key_type&, value_type&, void*);";
break;
}
case ck_set:
case ck_multiset:
{
- os << "load_all (value_type&, void*);";
+ os << "select (value_type&, void*);";
break;
}
}
os << endl;
- // delete_all
+ // update
+ //
+ if (smart)
+ {
+ os << "static void" << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "update (index_type, const value_type&, void*);";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ //os << "update (const key_type&, const value_type&, void*);";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ //os << "update (const value_type&, const value_type&, void*);";
+ break;
+ }
+ }
+
+ os << endl;
+ }
+
+ // delete_
//
os << "static void" << endl
- << "delete_all (void*);"
+ << "delete_ (";
+
+ if (smart)
+ {
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "index_type, ";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
+ }
+
+ os << "void*);"
<< endl;
// persist
//
if (!inverse)
os << "static void" << endl
- << "persist (const container_type&," << endl
- << "const " << db << "::binding& id," << endl
- << "statements_type&);"
+ << "persist (const container_type&, statements_type&);"
<< endl;
// load
//
os << "static void" << endl
- << "load (container_type&," << endl
- << "const " << db << "::binding& id," << endl
- << "statements_type&);"
+ << "load (container_type&, statements_type&);"
<< endl;
// update
//
if (!(inverse || readonly (member_path_, member_scope_)))
os << "static void" << endl
- << "update (const container_type&," << endl
- << "const " << db << "::binding& id," << endl
- << "statements_type&);"
+ << "update (const container_type&, statements_type&);"
<< endl;
// erase
//
if (!inverse)
+ {
os << "static void" << endl
- << "erase (const " << db << "::binding& id, statements_type&);"
+ << "erase (";
+
+ if (smart)
+ os << "const container_type*, ";
+
+ os << "statements_type&);"
<< endl;
+ }
- container_public_extra_post (m);
+ container_public_extra_post (m, c);
os << "};";
}
diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx
index 466e348..24e3a08 100644
--- a/odb/relational/inline.hxx
+++ b/odb/relational/inline.hxx
@@ -305,7 +305,8 @@ namespace relational
// erase (object_type)
//
- if (id != 0 && !poly && optimistic == 0)
+ if (id != 0 && !poly && optimistic == 0 &&
+ !has_a (c, test_smart_container))
{
os << "inline" << endl
<< "void " << traits << "::" << endl
diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx
index 5d29b27..a5bc360 100644
--- a/odb/relational/mssql/source.cxx
+++ b/odb/relational/mssql/source.cxx
@@ -833,7 +833,7 @@ namespace relational
virtual void
init_value_extra ()
{
- os << "sts.select_all_statement ().stream_result ();"
+ os << "sts.select_statement ().stream_result ();"
<< endl;
}
diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx
index f6cdfcd..8c03966 100644
--- a/odb/relational/oracle/source.cxx
+++ b/odb/relational/oracle/source.cxx
@@ -540,7 +540,7 @@ namespace relational
virtual void
init_value_extra ()
{
- os << "sts.select_all_statement ().stream_result ();"
+ os << "sts.select_statement ().stream_result ();"
<< endl;
}
};
diff --git a/odb/relational/pgsql/header.cxx b/odb/relational/pgsql/header.cxx
index 5141c6c..ef0f018 100644
--- a/odb/relational/pgsql/header.cxx
+++ b/odb/relational/pgsql/header.cxx
@@ -103,24 +103,36 @@ namespace relational
container_traits (base const& x): base (x) {}
virtual void
- container_public_extra_pre (semantics::data_member&)
+ container_public_extra_pre (semantics::data_member& m,
+ semantics::type& t)
{
if (!object (c_) || (abstract (c_) && !polymorphic (c_)))
return;
+ bool smart (!inverse (m, "value") && !unordered (m) &&
+ container_smart (t));
+
// Container statement names.
//
- os << "static const char select_all_name[];"
- << "static const char insert_one_name[];"
- << "static const char delete_all_name[];"
+ os << "static const char select_name[];"
+ << "static const char insert_name[];";
+
+ if (smart)
+ os << "static const char update_name[];";
+
+ os << "static const char delete_name[];"
<< endl;
// Container statement types.
//
- os << "static const unsigned int select_all_types[];"
- << "static const unsigned int insert_one_types[];"
- << "static const unsigned int delete_all_types[];"
- << endl;
+ os << "static const unsigned int select_types[];"
+ << "static const unsigned int insert_types[];";
+
+ if (smart)
+ os << "static const unsigned int update_types[];"
+ << "static const unsigned int delete_types[];";
+
+ os << endl;
}
};
entry<container_traits> container_traits_;
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
index e106758..46a0594 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/relational/pgsql/source.cxx
@@ -791,6 +791,14 @@ namespace relational
}
virtual void
+ container_cache_extra_args (bool used)
+ {
+ os << "," << endl
+ << db << "::native_binding&" << (used ? " idn" : "") << "," << endl
+ << "const unsigned int*" << (used ? " idt" : "");
+ }
+
+ virtual void
view_extra (type& c)
{
string const& n (class_fq_name (c));
@@ -866,10 +874,16 @@ namespace relational
if (!object (c_) || (abstract (c_) && !polymorphic (c_)))
return;
+ container_kind_type ck (container_kind (t));
string const& pn (public_name (m));
string scope (scope_ + "::" + flat_prefix_ + pn + "_traits");
+ semantics::data_member* inv_m (inverse (m, "value"));
+ bool inv (inv_m != 0);
+
+ bool smart (!inv && !unordered (m) && container_smart (t));
+
// Statment names.
//
@@ -881,29 +895,32 @@ namespace relational
class_fq_name (*top_object) + "_" + flat_prefix_ + pn));
os << "const char " << scope << "::" << endl
- << "select_all_name[] = " << strlit (fn + "_select_all") << ";"
+ << "select_name[] = " << strlit (fn + "_select") << ";"
<< endl
<< "const char " << scope << "::" << endl
- << "insert_one_name[] = " << strlit (fn + "_insert_one") << ";"
- << endl
- << "const char " << scope << "::" << endl
- << "delete_all_name[] = " << strlit (fn + "_delete_all") << ";"
+ << "insert_name[] = " << strlit (fn + "_insert") << ";"
+ << endl;
+
+ if (smart)
+ os << "const char " << scope << "::" << endl
+ << "update_name[] = " << strlit (fn + "_update") << ";"
+ << endl;
+
+ os << "const char " << scope << "::" << endl
+ << "delete_name[] = " << strlit (fn + "_delete") << ";"
<< endl;
// Statement types.
//
- semantics::data_member* inv_m (inverse (m, "value"));
- bool inv (inv_m != 0);
-
semantics::type& vt (container_vt (t));
semantics::type& idt (container_idt (m));
- // select_all statement types.
+ // select statement types.
//
{
os << "const unsigned int " << scope << "::" << endl
- << "select_all_types[] ="
+ << "select_types[] ="
<< "{";
statement_oids so (statement_where);
@@ -926,11 +943,11 @@ namespace relational
os << "};";
}
- // insert_one statement types.
+ // insert statement types.
//
{
os << "const unsigned int " << scope << "::" << endl
- << "insert_one_types[] ="
+ << "insert_types[] ="
<< "{";
if (!inv)
@@ -939,7 +956,7 @@ namespace relational
so.traverse (m, idt, "id", "object_id");
- switch (container_kind (t))
+ switch (ck)
{
case ck_ordered:
{
@@ -971,26 +988,96 @@ namespace relational
os << "};";
}
- // delete_all statement types.
+ // update statement types.
//
+ if (smart)
{
os << "const unsigned int " << scope << "::" << endl
- << "delete_all_types[] ="
+ << "update_types[] ="
<< "{";
- if (!inv)
+ statement_oids so (statement_where);
+
+ so.traverse (m, vt, "value", "value");
+ so.traverse (m, idt, "id", "object_id");
+
+ switch (ck)
{
- statement_oids so (statement_where);
- so.traverse (m, idt, "id", "object_id");
+ case ck_ordered:
+ {
+ if (!unordered (m))
+ so.traverse (m, container_it (t), "index", "index");
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ //so.traverse (m, container_kt (t), "key", "key");
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ //so.traverse (m, vt, "value", "value");
+ break;
+ }
+ }
+
+ os << "};";
+ }
+
+ // delete statement types.
+ //
+ if (smart)
+ {
+ os << "const unsigned int " << scope << "::" << endl
+ << "delete_types[] ="
+ << "{";
+
+ statement_oids so (statement_where);
+ so.traverse (m, idt, "id", "object_id");
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ if (!unordered (m))
+ so.traverse (m, container_it (t), "index", "index");
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ //so.traverse (m, container_kt (t), "key", "key");
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ //so.traverse (m, vt, "value", "value");
+ break;
+ }
}
- else
- os << "0";
os << "};";
}
}
};
entry<container_traits> container_traits_;
+
+ struct container_cache_init_members:
+ relational::container_cache_init_members
+ {
+ container_cache_init_members (base const& x): base (x) {}
+
+ virtual void
+ extra_members ()
+ {
+ os << ", idn, idt";
+ }
+ };
+ entry<container_cache_init_members> container_cache_init_members_;
+
}
}
}
diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx
index 661db71..fe6bbbd 100644
--- a/odb/relational/source.cxx
+++ b/odb/relational/source.cxx
@@ -73,6 +73,7 @@ traverse_object (type& c)
bool containers (has_a (c, test_container));
bool straight_containers (false);
bool straight_readwrite_containers (false);
+ bool smart_containers (false);
if (containers)
{
@@ -85,6 +86,10 @@ traverse_object (type& c)
// Inverse containers cannot be marked readonly.
//
straight_readwrite_containers = scn > has_a (c, test_readonly_container);
+
+ // Inverse containers cannot be smart.
+ //
+ smart_containers = has_a (c, test_smart_container);
}
}
@@ -418,8 +423,13 @@ traverse_object (type& c)
cm->traverse (c);
os << (containers ? "\n" : "")
- << "container_statement_cache_type (" << db << "::connection&" <<
- (containers ? " c" : "") << ")";
+ << "container_statement_cache_type (" << endl
+ << db << "::connection&" << (containers ? " c" : "") << "," << endl
+ << db << "::binding&" << (containers ? " id" : "");
+
+ container_cache_extra_args (containers);
+
+ os << ")";
instance<container_cache_init_members> im;
im->traverse (c);
@@ -1187,8 +1197,7 @@ traverse_object (type& c)
<< "}";
}
- if (cc.total != cc.id + cc.inverse + cc.readonly ||
- straight_readwrite_containers)
+ if (cc.total != cc.id + cc.inverse + cc.readonly)
{
os << "const binding& idb (sts.id_image_binding ());"
<< endl;
@@ -1395,10 +1404,6 @@ traverse_object (type& c)
if (delay_freeing_statement_result)
os << "sts.find_statement ().free_result ();";
}
-
- if (straight_readwrite_containers)
- os << "binding& idb (sts.id_image_binding ());"
- << endl;
}
if (straight_readwrite_containers)
@@ -1565,11 +1570,7 @@ traverse_object (type& c)
//
if (straight_containers)
{
- if (poly)
- os << "binding& idb (sts.id_image_binding ());"
- << endl;
-
- instance<container_calls> t (container_calls::erase_call);
+ instance<container_calls> t (container_calls::erase_id_call);
t->traverse (c);
}
@@ -1601,7 +1602,7 @@ traverse_object (type& c)
// erase (object)
//
- if (id != 0 && (poly || opt != 0))
+ if (id != 0 && (poly || opt != 0 || smart_containers))
{
os << "void " << traits << "::" << endl
<< "erase (database& db, const object_type& obj";
@@ -1632,22 +1633,14 @@ traverse_object (type& c)
<< "}";
// If we are database-poly-abstract but not C++-abstract, then make
- // sure we are not trying to persist an instance of an abstract class.
+ // sure we are not trying to erase an instance of an abstract class.
//
if (abst && !c.abstract ())
os << "if (top)" << endl
<< "throw abstract_class ();"
<< endl;
- // Determine the dynamic type of this object.
- //
- if (opt == 0)
- {
- os << "callback (db, obj, callback_event::pre_erase);"
- << "erase (db, id (obj), true, false);"
- << "callback (db, obj, callback_event::post_erase);";
- }
- else
+ if (opt != 0 || smart_containers)
{
string rsts (poly_derived ? "rsts" : "sts");
@@ -1684,135 +1677,179 @@ traverse_object (type& c)
<< endl;
}
- // Initialize id + managed column image.
+ // Smart containers case.
//
- os << "binding& idb (" << rsts << ".id_image_binding ());"
- << endl;
-
- if (!abst) // If we are poly-abstract, then top will always be false.
+ if (opt == 0)
{
- if (poly)
- os << "if (top)"
- << "{";
+ // Initialize id image.
+ //
+ if (!abst) // If we are poly-abstract, then top will always be false.
+ {
+ if (poly)
+ os << "if (top)"
+ << "{";
- if (!opt_ma_get->synthesized)
- os << "// From " << location_string (opt_ma_get->loc, true) << endl;
+ os << "id_image_type& i (" << rsts << ".id_image ());"
+ << "init (i, id);"
+ << endl;
- os << "const version_type& v (" << endl
- << opt_ma_get->translate ("obj") << ");"
- << "id_image_type& i (" << rsts << ".id_image ());"
- << "init (i, id, &v);"
- << endl;
+ os << "binding& idb (" << rsts << ".id_image_binding ());"
+ << "if (i.version != " << rsts << ".id_image_version () || " <<
+ "idb.version == 0)"
+ << "{"
+ << "bind (idb.bind, i);"
+ << rsts << ".id_image_version (i.version);"
+ << "idb.version++;"
+ << "}";
+
+ if (poly)
+ os << "}";
+ }
- // To update the id part of the optimistic id binding we have
- // to do it indirectly via the id binding, since both id and
- // optimistic id bindings just point to the suffix of the
- // update bind array (see object_statements).
+ // Erase containers first so that there are no reference
+ // violations (we don't want to rely on ON DELETE CASCADE
+ // here since in case of a custom schema, it might not be
+ // there).
//
- os << "binding& oidb (" << rsts << ".optimistic_id_image_binding ());"
- << "if (i.version != " << rsts <<
- ".optimistic_id_image_version () ||" << endl
- << "oidb.version == 0)"
- << "{"
- // If the id binding is up-to-date, then that means optimistic
- // id binding is too and we just need to update the versions.
- //
- << "if (i.version != " << rsts << ".id_image_version () ||" << endl
- << "idb.version == 0)"
- << "{"
- << "bind (idb.bind, i);"
- // Update the id binding versions since we may use them later
- // to delete containers.
- //
- << rsts << ".id_image_version (i.version);"
- << "idb.version++;"
- << "}"
- << rsts << ".optimistic_id_image_version (i.version);"
- << "oidb.version++;"
- << "}";
+ instance<container_calls> t (container_calls::erase_obj_call);
+ t->traverse (c);
- if (poly)
- os << "}"; // if (top)
+ os << "if (sts.erase_statement ().execute () != 1)" << endl
+ << "throw object_not_persistent ();"
+ << endl;
}
-
- // If this is a derived type in a polymorphic hierarchy, then we
- // need to check the version (stored in root) before we go ahead
- // and start deleting things. Also use the same code for root with
- // containers since it is more efficient than the find_() method
- // below.
+ // Optimistic case.
//
- if (poly_derived || (poly && straight_containers))
+ else
{
- // Only do the check in the top-level call.
+ // Initialize id + managed column image.
//
if (!abst) // If we are poly-abstract, then top will always be false.
{
- os << "if (top)"
- << "{"
- << "version_type v;"
- << "root_traits::discriminator_ (" << rsts << ", id, 0, &v);"
- << endl;
+ if (poly)
+ os << "if (top)"
+ << "{";
if (!opt_ma_get->synthesized)
os << "// From " << location_string (opt_ma_get->loc, true) << endl;
- os << "if (v != " << opt_ma_get->translate ("obj") << ")" << endl
- << "throw object_changed ();"
+ os << "const version_type& v (" << endl
+ << opt_ma_get->translate ("obj") << ");"
+ << "id_image_type& i (" << rsts << ".id_image ());"
+ << "init (i, id, &v);"
+ << endl;
+
+ // To update the id part of the optimistic id binding we have
+ // to do it indirectly via the id binding, since both id and
+ // optimistic id bindings just point to the suffix of the
+ // update bind array (see object_statements).
+ //
+ os << "binding& oidb (" << rsts << ".optimistic_id_image_binding ());"
+ << "if (i.version != " << rsts <<
+ ".optimistic_id_image_version () ||" << endl
+ << "oidb.version == 0)"
+ << "{"
+ // If the id binding is up-to-date, then that means optimistic
+ // id binding is too and we just need to update the versions.
+ //
+ << "binding& idb (" << rsts << ".id_image_binding ());"
+ << "if (i.version != " << rsts << ".id_image_version () ||" << endl
+ << "idb.version == 0)"
+ << "{"
+ << "bind (idb.bind, i);"
+ // Update the id binding versions since we may use them later
+ // to delete containers.
+ //
+ << rsts << ".id_image_version (i.version);"
+ << "idb.version++;"
+ << "}"
+ << rsts << ".optimistic_id_image_version (i.version);"
+ << "oidb.version++;"
<< "}";
+
+ if (poly)
+ os << "}"; // if (top)
}
- }
- else if (straight_containers)
- {
- // Things get complicated here: we don't want to trash the
- // containers and then find out that the versions don't match
- // and we therefore cannot delete the object. After all, there
- // is no guarantee that the user will abort the transaction.
- // In fact, a perfectly reasonable scenario is to reload the
- // object, re-check the condition, decide not to delete the
- // object, and then commit the transaction.
- //
- // There doesn't seem to be anything better than first making
- // sure we can delete the object, then deleting the container
- // data, and then deleting the object. To check that we can
- // delete the object we are going to use find_() and then
- // compare the versions. A special-purpose SELECT query would
- // have been more efficient but it would complicated and bloat
- // things significantly.
+
+ // If this is a derived type in a polymorphic hierarchy, then we
+ // need to check the version (stored in root) before we go ahead
+ // and start deleting things. Also use the same code for root with
+ // containers since it is more efficient than the find_() method
+ // below.
//
- os << "if (!find_ (sts, &id))" << endl
- << "throw object_changed ();"
- << endl;
+ if (poly_derived || (poly && straight_containers))
+ {
+ // Only do the check in the top-level call.
+ //
+ if (!abst) // If we are poly-abstract, then top will always be false.
+ {
+ os << "if (top)"
+ << "{"
+ << "version_type v;"
+ << "root_traits::discriminator_ (" << rsts << ", id, 0, &v);"
+ << endl;
- if (delay_freeing_statement_result)
- os << "sts.find_statement ().free_result ();"
+ if (!opt_ma_get->synthesized)
+ os << "// From " << location_string (opt_ma_get->loc, true) << endl;
+
+ os << "if (v != " << opt_ma_get->translate ("obj") << ")" << endl
+ << "throw object_changed ();"
+ << "}";
+ }
+ }
+ else if (straight_containers)
+ {
+ // Things get complicated here: we don't want to trash the
+ // containers and then find out that the versions don't match
+ // and we therefore cannot delete the object. After all, there
+ // is no guarantee that the user will abort the transaction.
+ // In fact, a perfectly reasonable scenario is to reload the
+ // object, re-check the condition, decide not to delete the
+ // object, and then commit the transaction.
+ //
+ // There doesn't seem to be anything better than first making
+ // sure we can delete the object, then deleting the container
+ // data, and then deleting the object. To check that we can
+ // delete the object we are going to use find_() and then
+ // compare the versions. A special-purpose SELECT query would
+ // have been more efficient but it would complicated and bloat
+ // things significantly.
+ //
+ os << "if (!find_ (sts, &id))" << endl
+ << "throw object_changed ();"
<< endl;
- if (!opt_ma_get->synthesized)
- os << "// From " << location_string (opt_ma_get->loc, true) << endl;
+ if (delay_freeing_statement_result)
+ os << "sts.find_statement ().free_result ();"
+ << endl;
- os << "if (version (sts.image ()) != " <<
- opt_ma_get->translate ("obj") << ")" << endl
- << "throw object_changed ();"
- << endl;
- }
+ if (!opt_ma_get->synthesized)
+ os << "// From " << location_string (opt_ma_get->loc, true) << endl;
- // Erase containers first so that there are no reference
- // violations (we don't want to rely on ON DELETE CASCADE
- // here since in case of a custom schema, it might not be
- // there).
- //
- if (straight_containers)
- {
- instance<container_calls> t (container_calls::erase_call);
- t->traverse (c);
- }
+ os << "if (version (sts.image ()) != " <<
+ opt_ma_get->translate ("obj") << ")" << endl
+ << "throw object_changed ();"
+ << endl;
+ }
- const char* st (
- poly_derived ? "erase_statement" : "optimistic_erase_statement");
+ // Erase containers first so that there are no reference
+ // violations (we don't want to rely on ON DELETE CASCADE
+ // here since in case of a custom schema, it might not be
+ // there).
+ //
+ if (straight_containers)
+ {
+ instance<container_calls> t (container_calls::erase_obj_call);
+ t->traverse (c);
+ }
- os << "if (sts." << st << " ().execute () != 1)" << endl
- << "throw object_changed ();"
- << endl;
+ const char* st (
+ poly_derived ? "erase_statement" : "optimistic_erase_statement");
+
+ os << "if (sts." << st << " ().execute () != 1)" << endl
+ << "throw object_changed ();"
+ << endl;
+ }
if (poly_derived)
{
@@ -1841,6 +1878,16 @@ traverse_object (type& c)
os << "}";
}
}
+ else if (smart_containers)
+ {
+
+ }
+ else
+ {
+ os << "callback (db, obj, callback_event::pre_erase);"
+ << "erase (db, id (obj), true, false);"
+ << "callback (db, obj, callback_event::post_erase);";
+ }
os << "}";
}
@@ -2390,8 +2437,6 @@ traverse_object (type& c)
if (containers)
{
- os << db << "::binding& idb (sts.id_image_binding ());"
- << endl;
instance<container_calls> t (container_calls::load_call);
t->traverse (c);
}
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index dfa6ebf..717d91d 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -1889,6 +1889,10 @@ namespace relational
}
}
+ bool smart (!inverse &&
+ (ck != ck_ordered || ordered) &&
+ container_smart (t));
+
if (generate_grow)
grow = grow || context::grow (m, vt, "value");
@@ -1922,11 +1926,34 @@ namespace relational
qname table (table_name (m, table_prefix_));
string qtable (quote_id (table));
instance<object_columns_list> id_cols;
+ instance<object_columns_list> ik_cols; // index/key columns
+
+ if (smart)
+ {
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ ik_cols->traverse (m, *it, "index", "index");
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
+ }
- // select_all_statement
+ // select_statement
//
os << "const char " << scope << "::" << endl
- << "select_all_statement[] =" << endl;
+ << "select_statement[] =" << endl;
if (inverse)
{
@@ -2083,10 +2110,10 @@ namespace relational
os << ";"
<< endl;
- // insert_one_statement
+ // insert_statement
//
os << "const char " << scope << "::" << endl
- << "insert_one_statement[] =" << endl;
+ << "insert_statement[] =" << endl;
if (inverse)
os << strlit ("") << ";"
@@ -2148,10 +2175,57 @@ namespace relational
<< endl;
}
- // delete_all_statement
+ // update_statement
+ //
+ if (smart)
+ {
+ os << "const char " << scope << "::" << endl
+ << "update_statement[] =" << endl
+ << strlit ("UPDATE " + qtable + " SET ");
+
+ instance<query_parameters> qp (table);
+ statement_columns sc;
+ {
+ query_parameters* p (qp.get ()); // Imperfect forwarding.
+ statement_kind sk (statement_update); // Imperfect forwarding.
+ instance<object_columns> t (sk, sc, p);
+ t->traverse (m, vt, "value", "value");
+ process_statement_columns (sc, statement_update);
+ }
+
+ for (statement_columns::const_iterator i (sc.begin ()),
+ e (sc.end ()); i != e;)
+ {
+ string const& c (i->column);
+ os << endl
+ << strlit (c + (++i != e ? "," : ""));
+ }
+
+ for (object_columns_list::iterator b (id_cols->begin ()), i (b);
+ i != id_cols->end (); ++i)
+ {
+ os << endl
+ << strlit ((i == b ? " WHERE " : " AND ") +
+ quote_id (i->name) + "=" +
+ convert_to (qp->next (), i->type, *i->member));
+ }
+
+ for (object_columns_list::iterator b (ik_cols->begin ()), i (b);
+ i != ik_cols->end (); ++i)
+ {
+ os << endl
+ << strlit (" AND " + quote_id (i->name) + "=" +
+ convert_to (qp->next (), i->type, *i->member));
+ }
+
+ os << ";"
+ << endl;
+ }
+
+ // delete_statement
//
os << "const char " << scope << "::" << endl
- << "delete_all_statement[] =" << endl;
+ << "delete_statement[] =" << endl;
if (inverse)
os << strlit ("") << ";"
@@ -2171,6 +2245,18 @@ namespace relational
convert_to (qp->next (), i->type, *i->member));
}
+ if (smart)
+ {
+ for (object_columns_list::iterator b (ik_cols->begin ()), i (b);
+ i != ik_cols->end (); ++i)
+ {
+ os << endl
+ << strlit (" AND " + quote_id (i->name) +
+ (ck == ck_ordered ? ">=" : "=") +
+ convert_to (qp->next (), i->type, *i->member));
+ }
+ }
+
os << ";"
<< endl;
}
@@ -2183,18 +2269,20 @@ namespace relational
// Functions.
//
- // bind()
+ // bind (cond_image_type)
//
+ if (smart)
{
- // bind (cond_image_type)
- //
os << "void " << scope << "::" << endl
<< "bind (" << bind_vector << " b," << endl
<< "const " << bind_vector << " id," << endl
<< "std::size_t id_size," << endl
<< "cond_image_type& c)"
<< "{"
- << "ODB_POTENTIALLY_UNUSED (c);"
+ << "using namespace " << db << ";"
+ << endl
+ << "statement_kind sk (statement_select);"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
<< endl
<< "std::size_t n (0);"
<< endl;
@@ -2209,11 +2297,6 @@ namespace relational
// We don't need to update the bind index since this is the
// last element.
//
- // 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:
@@ -2248,12 +2331,12 @@ namespace relational
break;
}
}
-#endif
-
os << "}";
+ }
- // bind (data_image_type)
- //
+ // bind (data_image_type)
+ //
+ {
os << "void " << scope << "::" << endl
<< "bind (" << bind_vector << " b," << endl
<< "const " << bind_vector << " id," << endl
@@ -2329,6 +2412,84 @@ namespace relational
os << "}";
}
+ // bind (cond_image, data_image) (update)
+ //
+ if (smart)
+ {
+ os << "void " << scope << "::" << endl
+ << "bind (" << bind_vector << " b," << endl
+ << "const " << bind_vector << " id," << endl
+ << "std::size_t id_size," << endl
+ << "cond_image_type& c," << endl
+ << "data_image_type& d)"
+ << "{"
+ << "using namespace " << db << ";"
+ << endl
+ << "statement_kind sk (statement_update);"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
+ << endl
+ << "std::size_t n (0);"
+ << endl;
+
+ os << "// key" << endl
+ << "//" << endl;
+ instance<bind_member> bm ("value_", "d", vt, "value_type", "value");
+ bm->traverse (m);
+
+ if (semantics::class_* c = composite_wrapper (vt))
+ os << "n += " << column_count (*c).total << "UL;"
+ << endl;
+ else
+ os << "n++;"
+ << endl;
+
+ os << "// object_id" << endl
+ << "//" << endl
+ << "if (id != 0)" << endl
+ << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));"
+ << "n += id_size;"
+ << endl;
+
+ // We don't need to update the bind index since this is the
+ // last element.
+ //
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ if (ordered)
+ {
+ os << "// index" << endl
+ << "//" << endl;
+ instance<bind_member> bm (
+ "index_", "c", *it, "index_type", "index");
+ bm->traverse (m);
+ }
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "// key" << endl
+ << "//" << endl;
+ instance<bind_member> bm ("key_", "c", *kt, "key_type", "key");
+ bm->traverse (m);
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "// value" << endl
+ << "//" << endl;
+ instance<bind_member> bm (
+ "value_", "c", vt, "value_type", "value");
+ bm->traverse (m);
+ break;
+ }
+ }
+ os << "}";
+ }
+
// grow ()
//
if (generate_grow)
@@ -2393,7 +2554,7 @@ namespace relational
case ck_ordered:
{
if (ordered)
- os << "init (data_image_type& i, index_type j, " <<
+ os << "init (data_image_type& i, index_type* j, " <<
"const value_type& v)";
else
os << "init (data_image_type& i, const value_type& v)";
@@ -2402,7 +2563,7 @@ namespace relational
case ck_map:
case ck_multimap:
{
- os << "init (data_image_type& i, const key_type& k, " <<
+ os << "init (data_image_type& i, const key_type* k, " <<
"const value_type& v)";
break;
}
@@ -2432,10 +2593,11 @@ namespace relational
if (ordered)
{
os << "// index" << endl
- << "//" << endl;
+ << "//" << endl
+ << "if (j != 0)";
instance<init_image_member> im (
- "index_", "j", *it, "index_type", "index");
+ "index_", "*j", *it, "index_type", "index");
im->traverse (m);
}
break;
@@ -2444,10 +2606,11 @@ namespace relational
case ck_multimap:
{
os << "// key" << endl
- << "//" << endl;
+ << "//" << endl
+ << "if (k != 0)";
instance<init_image_member> im (
- "key_", "k", *kt, "key_type", "key");
+ "key_", "*k", *kt, "key_type", "key");
im->traverse (m);
break;
@@ -2474,6 +2637,52 @@ namespace relational
os << "}";
}
+ // init (cond_image)
+ //
+ if (smart)
+ {
+ os << "void " << scope << "::" << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "init (cond_image_type& i, index_type j)"
+ << "{"
+ << "using namespace " << db << ";"
+ << endl
+ << "statement_kind sk (statement_select);"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
+ << endl;
+
+ instance<init_image_member> im (
+ "index_", "j", *it, "index_type", "index");
+ im->traverse (m);
+
+ os << "}";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ // Need to handle growth.
+ //
+ // os << "init (data_image_type&, const key_type&);";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ // Need to handle growth.
+ //
+ // os << "init (data_image_type&, const value_type&);";
+ break;
+ }
+ }
+
+ os << endl;
+ }
+
// init (data)
//
os << "void " << scope << "::" << endl;
@@ -2546,7 +2755,7 @@ namespace relational
}
os << "}";
- // insert_one
+ // insert
//
{
string ia, ka, va, da;
@@ -2565,7 +2774,7 @@ namespace relational
{
case ck_ordered:
{
- os << "insert_one (index_type" << ia << ", " <<
+ os << "insert (index_type" << ia << ", " <<
"const value_type&" << va << ", " <<
"void*" << da << ")";
break;
@@ -2573,7 +2782,7 @@ namespace relational
case ck_map:
case ck_multimap:
{
- os << "insert_one (const key_type&" << ka << ", " <<
+ os << "insert (const key_type&" << ka << ", " <<
"const value_type&" << va << ", " <<
"void*" << da << ")";
break;
@@ -2581,7 +2790,7 @@ namespace relational
case ck_set:
case ck_multiset:
{
- os << "insert_one (const value_type&" << va << ", " <<
+ os << "insert (const value_type&" << va << ", " <<
"void*" << da << ")";
break;
}
@@ -2594,7 +2803,6 @@ namespace relational
os << "using namespace " << db << ";"
<< endl
<< "statements_type& sts (*static_cast< statements_type* > (d));"
- << "binding& b (sts.data_image_binding ());"
<< "data_image_type& di (sts.data_image ());"
<< endl;
@@ -2602,13 +2810,13 @@ namespace relational
{
case ck_ordered:
{
- os << "init (di, " << (ordered ? "i, " : "") << "v);";
+ os << "init (di, " << (ordered ? "&i, " : "") << "v);";
break;
}
case ck_map:
case ck_multimap:
{
- os << "init (di, k, v);";
+ os << "init (di, &k, v);";
break;
}
case ck_set:
@@ -2620,22 +2828,89 @@ namespace relational
}
os << endl
- << "if (di.version != sts.data_image_version ())"
+ << "if (sts.data_binding_test_version ())"
<< "{"
- << "bind (b.bind, 0, sts.id_binding ().count, di);"
- << "sts.data_image_version (di.version);"
- << "b.version++;"
- << "sts.select_image_binding ().version++;"
+ << "const binding& id (sts.id_binding ());"
+ << "bind (sts.data_bind (), id.bind, id.count, di);"
+ << "sts.data_binding_update_version ();"
<< "}"
- << "if (!sts.insert_one_statement ().execute ())" << endl
+ << "if (!sts.insert_statement ().execute ())" << endl
<< "throw object_already_persistent ();";
}
os << "}";
}
+ // update
+ //
+ if (smart)
+ {
+ os << "void " << scope << "::" << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "update (index_type i, const value_type& v, void* d)";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
- // load_all
+ os << "{";
+
+ os << "using namespace " << db << ";"
+ << endl
+ << "statements_type& sts (*static_cast< statements_type* > (d));"
+ << "cond_image_type& ci (sts.cond_image ());"
+ << "data_image_type& di (sts.data_image ());"
+ << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "init (ci, i);";
+ os << "init (di, 0, v);";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ //os << "init (di, 0, v);";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ //os << "init (di, v);";
+ break;
+ }
+ }
+
+ os << endl
+ << "if (sts.update_binding_test_version ())"
+ << "{"
+ << "const binding& id (sts.id_binding ());"
+ << "bind (sts.update_bind (), id.bind, id.count, ci, di);"
+ << "sts.update_binding_update_version ();"
+ << "}";
+
+ os << "if (sts.update_statement ().execute () == 0)" << endl
+ << "throw object_not_persistent ();"
+ << "}";
+ }
+
+ // select
//
os << "bool " << scope << "::" << endl;
@@ -2643,26 +2918,27 @@ namespace relational
{
case ck_ordered:
{
- os << "load_all (index_type&" << (ordered ? " i" : "") <<
+ os << "select (index_type&" << (ordered ? " i" : "") <<
", value_type& v, void* d)";
break;
}
case ck_map:
case ck_multimap:
{
- os << "load_all (key_type& k, value_type& v, void* d)";
+ os << "select (key_type& k, value_type& v, void* d)";
break;
}
case ck_set:
case ck_multiset:
{
- os << "load_all (value_type& v, void* d)";
+ os << "select (value_type& v, void* d)";
break;
}
}
os << "{"
<< "using namespace " << db << ";"
+ << "using " << db << "::select_statement;" // Conflicts.
<< endl
<< "statements_type& sts (*static_cast< statements_type* > (d));"
<< "data_image_type& di (sts.data_image ());";
@@ -2698,27 +2974,21 @@ namespace relational
// If we are loading an eager pointer, then the call to init
// above executes other statements which potentially could
- // change the image.
+ // change the image, including the id.
//
if (eager_ptr)
{
- os << "const binding& idb (sts.id_binding ());"
- << endl
- << "if (di.version != sts.data_image_version () ||" << endl
- << "idb.version != sts.data_id_binding_version ())"
+ os << "if (sts.data_binding_test_version ())"
<< "{"
- << "binding& b (sts.data_image_binding ());"
- << "bind (b.bind, idb.bind, idb.count, di);"
- << "sts.data_image_version (di.version);"
- << "sts.data_id_binding_version (idb.version);"
- << "b.version++;"
- << "sts.select_image_binding ().version++;"
+ << "const binding& id (sts.id_binding ());"
+ << "bind (sts.data_bind (), id.bind, id.count, di);"
+ << "sts.data_binding_update_version ();"
<< "}";
}
// Fetch next.
//
- os << "select_statement& st (sts.select_all_statement ());"
+ os << "select_statement& st (sts.select_statement ());"
<< "select_statement::result r (st.fetch ());";
if (grow)
@@ -2727,13 +2997,12 @@ namespace relational
<< "{"
<< "grow (di, sts.select_image_truncated ());"
<< endl
- << "if (di.version != sts.data_image_version ())"
+ << "if (sts.data_binding_test_version ())"
<< "{"
- << "binding& b (sts.data_image_binding ());"
- << "bind (b.bind, 0, sts.id_binding ().count, di);"
- << "sts.data_image_version (di.version);"
- << "b.version++;"
- << "sts.select_image_binding ().version++;"
+ // Id cannot change.
+ //
+ << "bind (sts.data_bind (), 0, sts.id_binding ().count, di);"
+ << "sts.data_binding_update_version ();"
<< "st.refetch ();"
<< "}"
<< "}";
@@ -2741,17 +3010,77 @@ namespace relational
os << "return r != select_statement::no_data;"
<< "}";
- // delete_all
+ // delete_
//
os << "void " << scope << "::" << endl
- << "delete_all (void*" << (inverse ? "" : " d") << ")"
+ << "delete_ (";
+
+ if (smart)
+ {
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "index_type i, ";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
+ }
+
+ os << "void*" << (inverse ? "" : " d") << ")"
<< "{";
if (!inverse)
+ {
os << "using namespace " << db << ";"
<< endl
- << "statements_type& sts (*static_cast< statements_type* > (d));"
- << "sts.delete_all_statement ().execute ();";
+ << "statements_type& sts (*static_cast< statements_type* > (d));";
+
+ if (smart)
+ {
+ os << "cond_image_type& ci (sts.cond_image ());"
+ << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "init (ci, i);";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
+
+ os << endl
+ << "if (sts.cond_binding_test_version ())"
+ << "{"
+ << "const binding& id (sts.id_binding ());"
+ << "bind (sts.cond_bind (), id.bind, id.count, ci);"
+ << "sts.cond_binding_update_version ();"
+ << "}";
+ }
+
+ os << "sts.delete_statement ().execute ();";
+ }
os << "}";
@@ -2760,26 +3089,14 @@ namespace relational
if (!inverse)
{
os << "void " << scope << "::" << endl
- << "persist (const container_type& c," << endl
- << "const " << db << "::binding& id," << endl
- << "statements_type& sts)"
+ << "persist (const container_type& c, statements_type& sts)"
<< "{"
<< "using namespace " << db << ";"
<< endl
- << "binding& b (sts.data_image_binding ());"
- << "if (id.version != sts.data_id_binding_version () || " <<
- "b.version == 0)"
- << "{"
- << "bind (b.bind, id.bind, id.count, sts.data_image ());"
- << "sts.data_id_binding_version (id.version);"
- << "b.version++;"
- << "sts.select_image_binding ().version++;"
- << "}"
- << "sts.id_binding (id);"
<< "functions_type& fs (sts.functions ());";
- if (ck == ck_ordered)
- os << "fs.ordered (" << (ordered ? "true" : "false") << ");";
+ if (!smart && ck == ck_ordered)
+ os << "fs.ordered_ = " << (ordered ? "true" : "false") << ";";
os << "container_traits_type::persist (c, fs);"
<< "}";
@@ -2788,30 +3105,21 @@ namespace relational
// load
//
os << "void " << scope << "::" << endl
- << "load (container_type& c," << endl
- << "const " << db << "::binding& id," << endl
- << "statements_type& sts)"
+ << "load (container_type& c, statements_type& sts)"
<< "{"
<< "using namespace " << db << ";"
+ << "using " << db << "::select_statement;" // Conflicts.
<< endl
- << "binding& db (sts.data_image_binding ());"
- << "if (id.version != sts.data_id_binding_version () || " <<
- "db.version == 0)"
- << "{"
- << "bind (db.bind, id.bind, id.count, sts.data_image ());"
- << "sts.data_id_binding_version (id.version);"
- << "db.version++;"
- << "sts.select_image_binding ().version++;"
- << "}"
- << "binding& cb (sts.cond_image_binding ());"
- << "if (id.version != sts.cond_id_binding_version () || " <<
- "cb.version == 0)"
+ << "const binding& id (sts.id_binding ());"
+ << endl
+ << "if (sts.data_binding_test_version ())"
<< "{"
- << "bind (cb.bind, id.bind, id.count, sts.cond_image ());"
- << "sts.cond_id_binding_version (id.version);"
- << "cb.version++;"
+ << "bind (sts.data_bind (), id.bind, id.count, sts.data_image ());"
+ << "sts.data_binding_update_version ();"
<< "}"
- << "select_statement& st (sts.select_all_statement ());"
+ // We use the id binding directly so no need to check cond binding.
+ //
+ << "select_statement& st (sts.select_statement ());"
<< "st.execute ();"
<< "auto_result ar (st);";
@@ -2830,23 +3138,22 @@ namespace relational
<< "data_image_type& di (sts.data_image ());"
<< "grow (di, sts.select_image_truncated ());"
<< endl
- << "if (di.version != sts.data_image_version ())"
+ << "if (sts.data_binding_test_version ())"
<< "{"
- << "bind (db.bind, 0, id.count, sts.data_image ());"
- << "sts.data_image_version (di.version);"
- << "db.version++;"
- << "sts.select_image_binding ().version++;"
+ // Id cannot change.
+ //
+ << "bind (sts.data_bind (), 0, id.count, di);"
+ << "sts.data_binding_update_version ();"
<< "st.refetch ();"
<< "}"
<< "}";
os << "bool more (r != select_statement::no_data);"
<< endl
- << "sts.id_binding (id);"
<< "functions_type& fs (sts.functions ());";
- if (ck == ck_ordered)
- os << "fs.ordered (" << (ordered ? "true" : "false") << ");";
+ if (!smart && ck == ck_ordered)
+ os << "fs.ordered_ = " << (ordered ? "true" : "false") << ";";
os << "container_traits_type::load (c, more, fs);"
<< "}";
@@ -2856,37 +3163,21 @@ namespace relational
if (!(inverse || readonly (member_path_, member_scope_)))
{
os << "void " << scope << "::" << endl
- << "update (const container_type& c," << endl
- << "const " << db << "::binding& id," << endl
- << "statements_type& sts)"
+ << "update (const container_type& c, statements_type& sts)"
<< "{"
<< "using namespace " << db << ";"
<< endl
- << "binding& db (sts.data_image_binding ());"
- << "if (id.version != sts.data_id_binding_version () || " <<
- "db.version == 0)"
- << "{"
- << "bind (db.bind, id.bind, id.count, sts.data_image ());"
- << "sts.data_id_binding_version (id.version);"
- << "db.version++;"
- << "sts.select_image_binding ().version++;"
- << "}"
- //
- // We may need cond if the specialization calls delete_all.
- //
- << "binding& cb (sts.cond_image_binding ());"
- << "if (id.version != sts.cond_id_binding_version () || " <<
- "cb.version == 0)"
+ << "const binding& id (sts.id_binding ());"
+ << endl
+ << "if (sts.data_binding_test_version ())"
<< "{"
- << "bind (cb.bind, id.bind, id.count, sts.cond_image ());"
- << "sts.cond_id_binding_version (id.version);"
- << "cb.version++;"
+ << "bind (sts.data_bind (), id.bind, id.count, sts.data_image ());"
+ << "sts.data_binding_update_version ();"
<< "}"
- << "sts.id_binding (id);"
<< "functions_type& fs (sts.functions ());";
- if (ck == ck_ordered)
- os << "fs.ordered (" << (ordered ? "true" : "false") << ");";
+ if (!smart && ck == ck_ordered)
+ os << "fs.ordered_ = " << (ordered ? "true" : "false") << ";";
os << "container_traits_type::update (c, fs);"
<< "}";
@@ -2897,25 +3188,21 @@ namespace relational
if (!inverse)
{
os << "void " << scope << "::" << endl
- << "erase (const " << db << "::binding& id, statements_type& sts)"
+ << "erase (";
+
+ if (smart)
+ os << "const container_type* c, ";
+
+ os << "statements_type& sts)"
<< "{"
<< "using namespace " << db << ";"
<< endl
- << "binding& b (sts.cond_image_binding ());"
- << "if (id.version != sts.cond_id_binding_version () || " <<
- "b.version == 0)"
- << "{"
- << "bind (b.bind, id.bind, id.count, sts.cond_image ());"
- << "sts.cond_id_binding_version (id.version);"
- << "b.version++;"
- << "}"
- << "sts.id_binding (id);"
<< "functions_type& fs (sts.functions ());";
- if (ck == ck_ordered)
- os << "fs.ordered (" << (ordered ? "true" : "false") << ");";
+ if (!smart && ck == ck_ordered)
+ os << "fs.ordered_ = " << (ordered ? "true" : "false") << ";";
- os << "container_traits_type::erase (fs);"
+ os << "container_traits_type::erase (" << (smart ? "c, " : "") << "fs);"
<< "}";
}
}
@@ -2937,10 +3224,16 @@ namespace relational
}
virtual void
- traverse_container (semantics::data_member& m, semantics::type&)
+ traverse_container (semantics::data_member& m, semantics::type& c)
{
+ bool smart (!context::inverse (m, "value") &&
+ !unordered (m) &&
+ container_smart (c));
+
string traits (flat_prefix_ + public_name (m) + "_traits");
- os << db << "::container_statements_impl< " << traits << " > " <<
+
+ os << db << "::" << (smart ? "smart_" : "") <<
+ "container_statements_impl< " << traits << " > " <<
flat_prefix_ << m.name () << ";";
}
};
@@ -2967,9 +3260,14 @@ namespace relational
os << "," << endl
<< " ";
- os << flat_prefix_ << m.name () << " (c)";
+ os << flat_prefix_ << m.name () << " (c, id";
+ extra_members ();
+ os << ")";
}
+ virtual void
+ extra_members () {}
+
protected:
bool first_;
};
@@ -2985,7 +3283,8 @@ namespace relational
persist_call,
load_call,
update_call,
- erase_call
+ erase_obj_call,
+ erase_id_call
};
container_calls (call_type call)
@@ -3001,7 +3300,7 @@ namespace relational
semantics::class_& c,
semantics::type* w)
{
- if (m == 0 || call_ == erase_call || modifier_ != 0)
+ if (m == 0 || call_ == erase_id_call || modifier_ != 0)
{
object_members_base::traverse_composite (m, c);
return;
@@ -3075,11 +3374,12 @@ namespace relational
}
virtual void
- traverse_container (semantics::data_member& m, semantics::type&)
+ traverse_container (semantics::data_member& m, semantics::type& c)
{
using semantics::type;
bool inverse (context::inverse (m, "value"));
+ bool smart (!inverse && !unordered (m) && container_smart (c));
// In certain cases we don't need to do anything.
//
@@ -3112,7 +3412,7 @@ namespace relational
throw operation_failed ();
}
- if (call_ != erase_call)
+ if (call_ != erase_id_call && (call_ != erase_obj_call || smart))
{
os << "{";
@@ -3178,7 +3478,6 @@ namespace relational
{
os << traits << "::persist (" << endl
<< var << "," << endl
- << "idb," << endl
<< "sts.container_statment_cache ()." << sts_name << ");";
break;
}
@@ -3186,7 +3485,6 @@ namespace relational
{
os << traits << "::load (" << endl
<< var << "," << endl
- << "idb," << endl
<< "sts.container_statment_cache ()." << sts_name << ");";
break;
}
@@ -3194,21 +3492,34 @@ namespace relational
{
os << traits << "::update (" << endl
<< var << "," << endl
- << "idb," << endl
<< "sts.container_statment_cache ()." << sts_name << ");";
break;
}
- case erase_call:
+ case erase_obj_call:
{
- os << traits << "::erase (" << endl
- << "idb," << endl
- << "sts.container_statment_cache ()." << sts_name << ");"
+ os << traits << "::erase (" << endl;
+
+ if (smart)
+ os << "&" << var << "," << endl;
+
+ os << "sts.container_statment_cache ()." << sts_name << ");"
+ << endl;
+ break;
+ }
+ case erase_id_call:
+ {
+ os << traits << "::erase (" << endl;
+
+ if (smart)
+ os << "0," << endl;
+
+ os << "sts.container_statment_cache ()." << sts_name << ");"
<< endl;
break;
}
}
- if (call_ != erase_call)
+ if (call_ != erase_id_call && (call_ != erase_obj_call || smart))
{
// Call the modifier if we are using a proper one.
//
@@ -3435,9 +3746,10 @@ namespace relational
//
virtual void
- object_extra (type&)
- {
- }
+ object_extra (type&) {}
+
+ virtual void
+ container_cache_extra_args (bool /*used*/) {}
virtual void
object_query_statement_ctor_args (type&,