summaryrefslogtreecommitdiff
path: root/odb-tests/evolution
diff options
context:
space:
mode:
Diffstat (limited to 'odb-tests/evolution')
-rw-r--r--odb-tests/evolution/add-column/driver.cxx125
-rw-r--r--odb-tests/evolution/add-column/model.hxx38
-rw-r--r--odb-tests/evolution/add-column/test1.hxx9
-rw-r--r--odb-tests/evolution/add-column/test2.hxx11
-rw-r--r--odb-tests/evolution/add-column/test3.hxx11
-rw-r--r--odb-tests/evolution/add-foreign-key/driver.cxx173
-rw-r--r--odb-tests/evolution/add-foreign-key/model.hxx66
-rw-r--r--odb-tests/evolution/add-foreign-key/test1.hxx9
-rw-r--r--odb-tests/evolution/add-foreign-key/test2.hxx11
-rw-r--r--odb-tests/evolution/add-foreign-key/test3.hxx11
-rw-r--r--odb-tests/evolution/add-index/driver.cxx165
-rw-r--r--odb-tests/evolution/add-index/model.hxx33
-rw-r--r--odb-tests/evolution/add-index/test1.hxx9
-rw-r--r--odb-tests/evolution/add-index/test2.hxx11
-rw-r--r--odb-tests/evolution/add-index/test3.hxx11
-rw-r--r--odb-tests/evolution/add-table/driver.cxx140
-rw-r--r--odb-tests/evolution/add-table/model.hxx48
-rw-r--r--odb-tests/evolution/add-table/test1.hxx9
-rw-r--r--odb-tests/evolution/add-table/test2.hxx11
-rw-r--r--odb-tests/evolution/add-table/test3.hxx11
-rw-r--r--odb-tests/evolution/alter-column/driver.cxx160
-rw-r--r--odb-tests/evolution/alter-column/model.hxx56
-rw-r--r--odb-tests/evolution/alter-column/test1.hxx9
-rw-r--r--odb-tests/evolution/alter-column/test2.hxx11
-rw-r--r--odb-tests/evolution/alter-column/test3.hxx11
-rw-r--r--odb-tests/evolution/combined/driver.cxx157
-rw-r--r--odb-tests/evolution/combined/model.hxx174
-rw-r--r--odb-tests/evolution/combined/test1.hxx9
-rw-r--r--odb-tests/evolution/combined/test2.hxx11
-rw-r--r--odb-tests/evolution/combined/test3.hxx11
-rw-r--r--odb-tests/evolution/data/driver.cxx178
-rw-r--r--odb-tests/evolution/data/model.hxx45
-rw-r--r--odb-tests/evolution/data/test1.hxx9
-rw-r--r--odb-tests/evolution/data/test2.hxx11
-rw-r--r--odb-tests/evolution/data/test3.hxx11
-rw-r--r--odb-tests/evolution/drop-column/driver.cxx126
-rw-r--r--odb-tests/evolution/drop-column/model.hxx59
-rw-r--r--odb-tests/evolution/drop-column/test1.hxx9
-rw-r--r--odb-tests/evolution/drop-column/test2.hxx11
-rw-r--r--odb-tests/evolution/drop-column/test3.hxx11
-rw-r--r--odb-tests/evolution/drop-foreign-key/driver.cxx145
-rw-r--r--odb-tests/evolution/drop-foreign-key/model.hxx50
-rw-r--r--odb-tests/evolution/drop-foreign-key/test1.hxx9
-rw-r--r--odb-tests/evolution/drop-foreign-key/test2.hxx11
-rw-r--r--odb-tests/evolution/drop-foreign-key/test3.hxx11
-rw-r--r--odb-tests/evolution/drop-index/driver.cxx154
-rw-r--r--odb-tests/evolution/drop-index/model.hxx33
-rw-r--r--odb-tests/evolution/drop-index/test1.hxx9
-rw-r--r--odb-tests/evolution/drop-index/test2.hxx11
-rw-r--r--odb-tests/evolution/drop-index/test3.hxx11
-rw-r--r--odb-tests/evolution/drop-table/driver.cxx168
-rw-r--r--odb-tests/evolution/drop-table/model.hxx94
-rw-r--r--odb-tests/evolution/drop-table/test1.hxx9
-rw-r--r--odb-tests/evolution/drop-table/test2.hxx11
-rw-r--r--odb-tests/evolution/drop-table/test3.hxx11
-rw-r--r--odb-tests/evolution/embedded/driver.cxx181
-rw-r--r--odb-tests/evolution/embedded/model.hxx45
-rw-r--r--odb-tests/evolution/embedded/test1.hxx9
-rw-r--r--odb-tests/evolution/embedded/test2.hxx11
-rw-r--r--odb-tests/evolution/embedded/test3.hxx11
-rw-r--r--odb-tests/evolution/soft-add/driver.cxx2219
-rw-r--r--odb-tests/evolution/soft-add/model.hxx504
-rw-r--r--odb-tests/evolution/soft-add/test1.hxx9
-rw-r--r--odb-tests/evolution/soft-add/test2.hxx11
-rw-r--r--odb-tests/evolution/soft-add/test3.hxx11
-rw-r--r--odb-tests/evolution/soft-delete/driver.cxx2202
-rw-r--r--odb-tests/evolution/soft-delete/model.hxx518
-rw-r--r--odb-tests/evolution/soft-delete/test1.hxx9
-rw-r--r--odb-tests/evolution/soft-delete/test2.hxx11
-rw-r--r--odb-tests/evolution/soft-delete/test3.hxx11
-rw-r--r--odb-tests/evolution/template/driver.cxx124
-rw-r--r--odb-tests/evolution/template/model.hxx40
-rw-r--r--odb-tests/evolution/template/template-vc10.vcxproj196
-rw-r--r--odb-tests/evolution/template/template-vc10.vcxproj.filters32
-rw-r--r--odb-tests/evolution/template/template-vc11.vcxproj200
-rw-r--r--odb-tests/evolution/template/template-vc11.vcxproj.filters32
-rw-r--r--odb-tests/evolution/template/template-vc12.vcxproj204
-rw-r--r--odb-tests/evolution/template/template-vc12.vcxproj.filters32
-rw-r--r--odb-tests/evolution/template/template-vc8.vcproj372
-rw-r--r--odb-tests/evolution/template/template-vc9.vcproj379
-rw-r--r--odb-tests/evolution/template/test1.hxx9
-rw-r--r--odb-tests/evolution/template/test2.hxx11
-rw-r--r--odb-tests/evolution/template/test3.hxx11
-rw-r--r--odb-tests/evolution/version/driver.cxx156
-rw-r--r--odb-tests/evolution/version/model.hxx45
-rw-r--r--odb-tests/evolution/version/test1.hxx9
-rw-r--r--odb-tests/evolution/version/test2.hxx11
-rw-r--r--odb-tests/evolution/version/test3.hxx11
88 files changed, 10364 insertions, 0 deletions
diff --git a/odb-tests/evolution/add-column/driver.cxx b/odb-tests/evolution/add-column/driver.cxx
new file mode 100644
index 0000000..d4eb396
--- /dev/null
+++ b/odb-tests/evolution/add-column/driver.cxx
@@ -0,0 +1,125 @@
+// file : evolution/add-column/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test adding a new column.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ object o (1);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+
+ assert (!p->str);
+ assert (p->num == 999);
+
+ // Migration.
+ //
+ p->str = "abc";
+ p->num = 123;
+ db->update (*p);
+
+ t.commit ();
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+
+ assert (p->str && *p->str == "abc");
+ assert (p->num == 123);
+
+ t.commit ();
+ }
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/add-column/model.hxx b/odb-tests/evolution/add-column/model.hxx
new file mode 100644
index 0000000..6ac9160
--- /dev/null
+++ b/odb-tests/evolution/add-column/model.hxx
@@ -0,0 +1,38 @@
+// file : evolution/add-column/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <string>
+
+#include <odb/core.hxx>
+#include <odb/nullable.hxx>
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+#if MODEL_VERSION == 3
+ odb::nullable<std::string> str;
+
+ #pragma db default(999)
+ unsigned long num;
+#endif
+ };
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/add-column/test1.hxx b/odb-tests/evolution/add-column/test1.hxx
new file mode 100644
index 0000000..b0d7fda
--- /dev/null
+++ b/odb-tests/evolution/add-column/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/add-column/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/add-column/test2.hxx b/odb-tests/evolution/add-column/test2.hxx
new file mode 100644
index 0000000..b62530a
--- /dev/null
+++ b/odb-tests/evolution/add-column/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/add-column/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/add-column/test3.hxx b/odb-tests/evolution/add-column/test3.hxx
new file mode 100644
index 0000000..b24dba1
--- /dev/null
+++ b/odb-tests/evolution/add-column/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/add-column/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/add-foreign-key/driver.cxx b/odb-tests/evolution/add-foreign-key/driver.cxx
new file mode 100644
index 0000000..177b615
--- /dev/null
+++ b/odb-tests/evolution/add-foreign-key/driver.cxx
@@ -0,0 +1,173 @@
+// file : evolution/add-foreign-key/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test adding a foreign key.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/config.hxx> // DATABASE_XXX
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ object o (1);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+#ifdef DATABASE_SQLITE
+ // In SQLite we can only add foreign keys inline in the column
+ // definition.
+ //
+ db->connection ()->execute ("PRAGMA foreign_keys=OFF");
+#endif
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ // Both pointers are now NULL.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+
+ assert (p->o1 == 0 && p->o2 == 0);
+
+ // Migration. The foreign key constraint is not yet there.
+ //
+ p->o1 = new object1 (1);
+ p->o2 = new object2 (1);
+ db->update (*p);
+
+ t.commit ();
+ }
+
+ // Migration. Add the missing objects.
+ //
+ object1 o1 (1);
+ object2 o2 (1);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->o1->id_ == 1);
+ assert (p->o2->id_ == 1);
+ t.commit ();
+ }
+
+ // Now the foreign key constraint is there.
+ //
+ try
+ {
+ object o (2);
+ o.o1 = new object1 (2);
+ o.o2 = new object2 (2);
+
+ transaction t (db->begin ());
+ db->persist (o);
+ assert (false);
+ }
+ catch (const odb::exception& ) {}
+
+ // As well as the NOT NULL.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ object o (3);
+ o.o2 = 0;
+
+ transaction t (db->begin ());
+ db->persist (o);
+ assert (false);
+ }
+ catch (const odb::exception& ) {}
+#endif
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/add-foreign-key/model.hxx b/odb-tests/evolution/add-foreign-key/model.hxx
new file mode 100644
index 0000000..f5fe26d
--- /dev/null
+++ b/odb-tests/evolution/add-foreign-key/model.hxx
@@ -0,0 +1,66 @@
+// file : evolution/add-foreign-key/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <string>
+
+#include <odb/core.hxx>
+
+#include <common/config.hxx> // DATABASE_XXX
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+#if MODEL_VERSION == 3
+ #pragma db object
+ struct object1
+ {
+ object1 (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+ };
+#endif
+
+ #pragma db object
+ struct object
+ {
+ #pragma db id
+ unsigned long id_;
+
+#if MODEL_VERSION == 2
+ object (unsigned long id = 0): id_ (id) {}
+#else
+ object1* o1;
+
+ // There is no support for changing a column to NOT NULL in SQLite.
+ //
+#ifndef ODB_DATABASE_SQLITE
+ #pragma db not_null
+#endif
+ object2* o2;
+
+ object (unsigned long id = 0): id_ (id), o1 (0), o2 (0) {}
+ ~object () {delete o1; delete o2;}
+#endif
+ };
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/add-foreign-key/test1.hxx b/odb-tests/evolution/add-foreign-key/test1.hxx
new file mode 100644
index 0000000..05c78c3
--- /dev/null
+++ b/odb-tests/evolution/add-foreign-key/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/add-foreign-key/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/add-foreign-key/test2.hxx b/odb-tests/evolution/add-foreign-key/test2.hxx
new file mode 100644
index 0000000..c57d9a1
--- /dev/null
+++ b/odb-tests/evolution/add-foreign-key/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/add-foreign-key/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/add-foreign-key/test3.hxx b/odb-tests/evolution/add-foreign-key/test3.hxx
new file mode 100644
index 0000000..c844469
--- /dev/null
+++ b/odb-tests/evolution/add-foreign-key/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/add-foreign-key/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/add-index/driver.cxx b/odb-tests/evolution/add-index/driver.cxx
new file mode 100644
index 0000000..689504e
--- /dev/null
+++ b/odb-tests/evolution/add-index/driver.cxx
@@ -0,0 +1,165 @@
+// file : evolution/add-index/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test adding a new index.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ object o0 (0);
+ o0.num = 123;
+
+ object o1 (1);
+ o1.num = 234;
+
+ object o2 (2);
+ o2.num = 234;
+
+ // Duplicates are ok.
+ //
+ {
+ transaction t (db->begin ());
+ db->persist (o0);
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ object o3 (3);
+ o3.num = 234;
+
+ // Duplicates are still ok but we need to remove them before the
+ // post migration step.
+ //
+ {
+ transaction t (db->begin ());
+ db->persist (o3);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (
+ "ORDER BY" + query::num + "," + query::id));
+
+ unsigned long prev (0);
+ for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ {
+ if (i->num == prev)
+ db->erase (*i);
+
+ prev = i->num;
+ }
+
+ t.commit ();
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p0 (db->load<object> (0));
+ auto_ptr<object> p1 (db->load<object> (1));
+
+ assert (p0->num == 123);
+ assert (p1->num == 234);
+
+ t.commit ();
+ }
+
+ try
+ {
+ object o2 (2);
+ o2.num = 234;
+
+ transaction t (db->begin ());
+ db->persist (o2);
+ assert (false);
+ }
+ catch (const odb::exception& ) {}
+
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/add-index/model.hxx b/odb-tests/evolution/add-index/model.hxx
new file mode 100644
index 0000000..fec75cc
--- /dev/null
+++ b/odb-tests/evolution/add-index/model.hxx
@@ -0,0 +1,33 @@
+// file : evolution/add-index/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <odb/core.hxx>
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+#if MODEL_VERSION == 3
+ #pragma db unique
+#endif
+ unsigned long num;
+ };
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/add-index/test1.hxx b/odb-tests/evolution/add-index/test1.hxx
new file mode 100644
index 0000000..1be2b5b
--- /dev/null
+++ b/odb-tests/evolution/add-index/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/add-index/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/add-index/test2.hxx b/odb-tests/evolution/add-index/test2.hxx
new file mode 100644
index 0000000..a0faca9
--- /dev/null
+++ b/odb-tests/evolution/add-index/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/add-index/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/add-index/test3.hxx b/odb-tests/evolution/add-index/test3.hxx
new file mode 100644
index 0000000..aab9c86
--- /dev/null
+++ b/odb-tests/evolution/add-index/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/add-index/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/add-table/driver.cxx b/odb-tests/evolution/add-table/driver.cxx
new file mode 100644
index 0000000..67b0f0e
--- /dev/null
+++ b/odb-tests/evolution/add-table/driver.cxx
@@ -0,0 +1,140 @@
+// file : evolution/add-table/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test adding a new table (object, container).
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/config.hxx> // DATABASE_XXX
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ // SQLite has broken foreign keys when it comes to DDL.
+ //
+#ifdef DATABASE_SQLITE
+ db->connection ()->execute ("PRAGMA foreign_keys=OFF");
+#endif
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+
+#ifdef DATABASE_SQLITE
+ db->connection ()->execute ("PRAGMA foreign_keys=ON");
+#endif
+ }
+
+ object o (1);
+ o.str = "abc";
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ object1 o1;
+ o1.nums.push_back (1);
+ o1.nums.push_back (2);
+ o1.nums.push_back (3);
+
+ {
+ transaction t (db->begin ());
+ o1.o = db->load<object> (1);
+ db->persist (o1);
+ t.commit ();
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ typedef odb::query<object1> query;
+ typedef odb::result<object1> result;
+
+ {
+ transaction t (db->begin ());
+
+ result r (db->query<object1> (query::o->str == "abc"));
+ result::iterator i (r.begin ()), e (r.end ());
+
+ assert (i != e &&
+ i->o->id_ == 1 &&
+ i->nums[0] == 1 && i->nums[1] == 2 && i->nums[2] == 3);
+ assert (++i == e);
+
+ t.commit ();
+ }
+
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/add-table/model.hxx b/odb-tests/evolution/add-table/model.hxx
new file mode 100644
index 0000000..208a156
--- /dev/null
+++ b/odb-tests/evolution/add-table/model.hxx
@@ -0,0 +1,48 @@
+// file : evolution/add-table/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <vector>
+#include <string>
+
+#include <odb/core.hxx>
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string str;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db object
+ struct object1
+ {
+ object1 (): o (0) {}
+ ~object1 () {delete o;}
+
+ #pragma db id auto
+ unsigned long id_;
+
+ object* o;
+ std::vector<int> nums;
+ };
+#endif
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/add-table/test1.hxx b/odb-tests/evolution/add-table/test1.hxx
new file mode 100644
index 0000000..adc51a1
--- /dev/null
+++ b/odb-tests/evolution/add-table/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/add-table/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/add-table/test2.hxx b/odb-tests/evolution/add-table/test2.hxx
new file mode 100644
index 0000000..ca03cef
--- /dev/null
+++ b/odb-tests/evolution/add-table/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/add-table/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/add-table/test3.hxx b/odb-tests/evolution/add-table/test3.hxx
new file mode 100644
index 0000000..39406a2
--- /dev/null
+++ b/odb-tests/evolution/add-table/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/add-table/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/alter-column/driver.cxx b/odb-tests/evolution/alter-column/driver.cxx
new file mode 100644
index 0000000..be63f05
--- /dev/null
+++ b/odb-tests/evolution/alter-column/driver.cxx
@@ -0,0 +1,160 @@
+// file : evolution/alter-column/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test altering a column.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+
+ // SQLite doesn't support altering of columns.
+ //
+#ifndef DATABASE_SQLITE
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ object o (1);
+ o.num = 123;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ // NULL is already in effect; NOT NULL is not yet.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+
+ assert (!p->str);
+ assert (p->num && *p->num == 123);
+ assert (!p->num1);
+
+ // Migration.
+ //
+ p->str = "abc";
+ p->num.reset ();
+ p->num1 = 123;
+ db->update (*p);
+
+ t.commit ();
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+
+ assert (p->str && *p->str == "abc");
+ assert (!p->num);
+
+ t.commit ();
+ }
+
+ // NOT NULL is now in effect.
+ //
+ try
+ {
+ object o2 (2);
+ o2.num1 = 234; // str is NULL
+
+ transaction t (db->begin ());
+ db->persist (o2);
+ assert (false);
+ }
+ catch (const odb::exception& ) {}
+
+ try
+ {
+ object o3 (3);
+ o3.str = "bcd"; // num1 is NULL
+
+ transaction t (db->begin ());
+ db->persist (o3);
+ assert (false);
+ }
+ catch (const odb::exception& ) {}
+
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+#endif // DATABASE_SQLITE
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/alter-column/model.hxx b/odb-tests/evolution/alter-column/model.hxx
new file mode 100644
index 0000000..fc6661c
--- /dev/null
+++ b/odb-tests/evolution/alter-column/model.hxx
@@ -0,0 +1,56 @@
+// file : evolution/alter-column/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <string>
+
+#include <odb/core.hxx>
+#include <odb/nullable.hxx>
+
+#include <common/config.hxx> // DATABASE_XXX
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ // SQLite doesn't support altering of columns.
+ //
+#ifndef DATABASE_SQLITE
+#if MODEL_VERSION == 2
+ odb::nullable<std::string> str;
+
+ unsigned long num;
+#else
+ // Use nullable to be able to access during migration.
+ //
+ #pragma db not_null
+ odb::nullable<std::string> str;
+
+ odb::nullable<unsigned long> num;
+
+ // Test adding NOT NULL column. It should be added NULL in pre
+ // and then converted to NOT NULL in post.
+ //
+ #pragma db not_null
+ odb::nullable<unsigned long> num1;
+#endif
+#endif
+ };
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/alter-column/test1.hxx b/odb-tests/evolution/alter-column/test1.hxx
new file mode 100644
index 0000000..9353558
--- /dev/null
+++ b/odb-tests/evolution/alter-column/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/alter-column/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/alter-column/test2.hxx b/odb-tests/evolution/alter-column/test2.hxx
new file mode 100644
index 0000000..e2dbed3
--- /dev/null
+++ b/odb-tests/evolution/alter-column/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/alter-column/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/alter-column/test3.hxx b/odb-tests/evolution/alter-column/test3.hxx
new file mode 100644
index 0000000..ac08e2f
--- /dev/null
+++ b/odb-tests/evolution/alter-column/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/alter-column/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/combined/driver.cxx b/odb-tests/evolution/combined/driver.cxx
new file mode 100644
index 0000000..88453c3
--- /dev/null
+++ b/odb-tests/evolution/combined/driver.cxx
@@ -0,0 +1,157 @@
+// file : evolution/combined/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Combined schema evolution test.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ object o ("1");
+ o.dui = 1;
+ o.anui = 1;
+ o.dnui = 1;
+ o.dc = 1;
+ o.dt.push_back (1);
+ o.aui = 1;
+
+#ifndef DATABASE_SQLITE
+ o.dfk = new object1 (1);
+ o.acn = 1;
+ o.acnn.reset ();
+ o.afk = 1;
+#endif
+
+ {
+ transaction t (db->begin ());
+#ifndef DATABASE_SQLITE
+ db->persist (o.dfk);
+#endif
+ db->persist (o);
+ t.commit ();
+ }
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> ("1"));
+
+ assert (p->ac1 == 999);
+ assert (!p->ac2);
+
+#ifndef DATABASE_SQLITE
+ assert (!p->ac3);
+#endif
+ // Migrate.
+ //
+ p->at.push_back ("abc");
+
+#ifndef DATABASE_SQLITE
+ p->dfk = 999;
+ p->ac3 = 1;
+ p->acn.reset ();
+ p->acnn = 1;
+#endif
+ db->update (*p);
+
+ t.commit ();
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> ("1"));
+
+ // Check post-migration.
+ //
+ assert (p->at[0] == "abc");
+
+#ifndef DATABASE_SQLITE
+ assert (p->dfk == 999);
+ assert (*p->ac3 == 1);
+ assert (!p->acn);
+ assert (*p->acnn == 1);
+#endif
+ t.commit ();
+ }
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/combined/model.hxx b/odb-tests/evolution/combined/model.hxx
new file mode 100644
index 0000000..e924943
--- /dev/null
+++ b/odb-tests/evolution/combined/model.hxx
@@ -0,0 +1,174 @@
+// file : evolution/combined/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <string>
+#include <vector>
+
+#include <odb/core.hxx>
+#include <odb/nullable.hxx>
+
+#include <common/config.hxx> // DATABASE_XXX
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+ #pragma db object
+ struct object1
+ {
+ object1 (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+ };
+
+ #pragma db object
+ struct object
+ {
+ #pragma db id
+ std::string id_;
+
+ //
+ // Pre pass 1.
+ //
+
+ // Drop unique index.
+ //
+#if MODEL_VERSION == 2
+ #pragma db unique
+#endif
+ unsigned long dui;
+
+ // Alter table drop foreign key. Not supported by SQLite.
+ //
+#ifndef DATABASE_SQLITE
+#if MODEL_VERSION == 2
+ object1* dfk;
+#else
+ #pragma db null
+ unsigned long dfk;
+#endif
+#endif
+
+ // Add table.
+ //
+#if MODEL_VERSION == 3
+ std::vector<std::string> at;
+#endif
+
+ // Add column.
+ //
+#if MODEL_VERSION == 3
+ #pragma db default(999)
+ unsigned long ac1;
+
+ odb::nullable<unsigned long> ac2;
+
+ // Initially added as NULL, converted to NOT NULL. Not supported by SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ #pragma db not_null
+ odb::nullable<unsigned long> ac3;
+#endif
+#endif
+
+ // Alter column NULL. Not supported by SQLite.
+ //
+#ifndef DATABASE_SQLITE
+#if MODEL_VERSION == 2
+ unsigned long acn;
+#else
+ odb::nullable<unsigned long> acn;
+#endif
+#endif
+
+ //
+ // Pre pass 2.
+ //
+
+ // Add non-unique indexes.
+ //
+#if MODEL_VERSION == 3
+ #pragma db index
+#endif
+ unsigned long anui;
+
+ //
+ // Post pass 1.
+ //
+
+ // Drop non-unique indexes.
+ //
+#if MODEL_VERSION == 2
+ #pragma db index
+#endif
+ unsigned long dnui;
+
+ //
+ // Post pass 2.
+ //
+
+ // Drop table.
+ //
+#if MODEL_VERSION == 2
+ std::vector<unsigned long> dt;
+#endif
+
+ // Drop column. Logical drop (set NULL) in SQLite.
+ //
+#if MODEL_VERSION == 2
+ unsigned long dc;
+#endif
+
+ // Alter column NOT NULL. Not supported by SQLite.
+ //
+#ifndef DATABASE_SQLITE
+#if MODEL_VERSION == 3
+ #pragma db not_null
+#endif
+ odb::nullable<unsigned long> acnn;
+#endif
+
+ // Alter table add foreign key. Not supported by SQLite.
+ //
+#ifndef DATABASE_SQLITE
+#if MODEL_VERSION == 2
+ #pragma db null
+ unsigned long afk;
+#else
+ object1* afk;
+#endif
+#endif
+
+ // Add unique index.
+ //
+#if MODEL_VERSION == 3
+ #pragma db unique
+#endif
+ unsigned long aui;
+
+ public:
+#ifndef DATABASE_SQLITE
+#if MODEL_VERSION == 2
+
+ object (std::string id = ""): id_ (id), dfk (0) {}
+ ~object () {delete dfk;}
+#else
+ object (std::string id = ""): id_ (id), afk (0) {}
+ ~object () {delete afk;}
+#endif
+#else
+ object (std::string id = ""): id_ (id) {}
+#endif
+ };
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/combined/test1.hxx b/odb-tests/evolution/combined/test1.hxx
new file mode 100644
index 0000000..1a18aff
--- /dev/null
+++ b/odb-tests/evolution/combined/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/combined/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/combined/test2.hxx b/odb-tests/evolution/combined/test2.hxx
new file mode 100644
index 0000000..8eb7ac8
--- /dev/null
+++ b/odb-tests/evolution/combined/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/combined/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/combined/test3.hxx b/odb-tests/evolution/combined/test3.hxx
new file mode 100644
index 0000000..05a052f
--- /dev/null
+++ b/odb-tests/evolution/combined/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/combined/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/data/driver.cxx b/odb-tests/evolution/data/driver.cxx
new file mode 100644
index 0000000..73cc852
--- /dev/null
+++ b/odb-tests/evolution/data/driver.cxx
@@ -0,0 +1,178 @@
+// file : evolution/data/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test data migration support.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/config.hxx> // DATABASE_XXX, HAVE_CXX11
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+void
+migrate1 (database& db)
+{
+ using namespace v2;
+ using namespace v3;
+
+ auto_ptr<object1> o1 (db.load<object1> (1));
+ object2 o2 (1);
+ o2.num = o1->num;
+ db.persist (o2);
+}
+
+void
+migrate2 (database& db)
+{
+ using namespace v2;
+ using namespace v3;
+
+ auto_ptr<object1> o1 (db.load<object1> (2));
+ object2 o2 (2);
+ o2.num = o1->num;
+ db.persist (o2);
+}
+
+static const data_migration_entry<3, 1> migrate2_entry (&migrate2);
+
+int
+main (int argc, char* argv[])
+{
+ schema_catalog::data_migration_function<3, 1> (&migrate1);
+
+#ifdef HAVE_CXX11
+ schema_catalog::data_migration_function<3, 1> (
+ [] (database& db)
+ {
+ using namespace v2;
+ using namespace v3;
+
+ auto_ptr<object1> o1 (db.load<object1> (11));
+ object2 o2 (11);
+ o2.num = o1->num;
+ db.persist (o2);
+ });
+#endif
+
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+
+ {
+ object1 o1 (1);
+ o1.num = 123;
+ db->persist (o1);
+ }
+
+ {
+ object1 o1 (2);
+ o1.num = 123;
+ db->persist (o1);
+ }
+
+#ifdef HAVE_CXX11
+ {
+ object1 o1 (11);
+ o1.num = 123;
+ db->persist (o1);
+ }
+#endif
+ t.commit ();
+ }
+ break;
+ }
+ case 2:
+ {
+ {
+ transaction t (db->begin ());
+
+ if (embedded)
+ schema_catalog::migrate (*db);
+ else
+ schema_catalog::migrate_data (*db);
+
+ t.commit ();
+ }
+
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ {
+ transaction t (db->begin ());
+
+ {
+ auto_ptr<object2> o2 (db->load<object2> (1));
+ assert (o2->num == 123);
+ }
+
+ {
+ auto_ptr<object2> o2 (db->load<object2> (2));
+ assert (o2->num == 123);
+ }
+
+#ifdef HAVE_CXX11
+ {
+ auto_ptr<object2> o2 (db->load<object2> (11));
+ assert (o2->num == 123);
+ }
+#endif
+ t.commit ();
+ }
+
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/data/model.hxx b/odb-tests/evolution/data/model.hxx
new file mode 100644
index 0000000..680bc55
--- /dev/null
+++ b/odb-tests/evolution/data/model.hxx
@@ -0,0 +1,45 @@
+// file : evolution/data/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <odb/core.hxx>
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+#if MODEL_VERSION == 2
+ #pragma db object
+ struct object1
+ {
+ object1 (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ int num;
+ };
+#endif
+
+#if MODEL_VERSION == 3
+ #pragma db object
+ struct object2
+ {
+ object2 (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ int num;
+ };
+#endif
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/data/test1.hxx b/odb-tests/evolution/data/test1.hxx
new file mode 100644
index 0000000..976ed04
--- /dev/null
+++ b/odb-tests/evolution/data/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/data/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/data/test2.hxx b/odb-tests/evolution/data/test2.hxx
new file mode 100644
index 0000000..bd72940
--- /dev/null
+++ b/odb-tests/evolution/data/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/data/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/data/test3.hxx b/odb-tests/evolution/data/test3.hxx
new file mode 100644
index 0000000..0f47099
--- /dev/null
+++ b/odb-tests/evolution/data/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/data/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/drop-column/driver.cxx b/odb-tests/evolution/drop-column/driver.cxx
new file mode 100644
index 0000000..7f0c253
--- /dev/null
+++ b/odb-tests/evolution/drop-column/driver.cxx
@@ -0,0 +1,126 @@
+// file : evolution/drop-column/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test dropping a column.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ object o (1);
+ o.str = "abc";
+ o.num = 123;
+ o.ptr = new object1 (1, 2);
+
+ {
+ transaction t (db->begin ());
+ db->persist (*o.ptr);
+ db->persist (o);
+ t.commit ();
+ }
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ // Things are still there.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+
+ assert (p->str == "abc");
+ assert (p->num == 123);
+ assert (p->ptr->id.x == 1 && p->ptr->id.y == 2);
+
+ t.commit ();
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ // Now they are gone.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->str == "" && p->ptr == 0);
+ db->erase<object1> (value (1, 2)); // SQLite logical delete test.
+ t.commit ();
+ }
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/drop-column/model.hxx b/odb-tests/evolution/drop-column/model.hxx
new file mode 100644
index 0000000..09b63b9
--- /dev/null
+++ b/odb-tests/evolution/drop-column/model.hxx
@@ -0,0 +1,59 @@
+// file : evolution/drop-column/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <string>
+
+#include <odb/core.hxx>
+#include <odb/nullable.hxx>
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+ #pragma db value
+ struct value
+ {
+ value (int x_ = 0, int y_ = 0): x (x_), y (y_) {}
+ int x;
+ int y;
+ };
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int x = 0, int y = 0): id (x, y) {}
+
+ #pragma db id
+ value id;
+ };
+
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id), ptr (0) {}
+ ~object () {delete ptr;}
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string str;
+ unsigned long num;
+ object1* ptr;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) deleted(3)
+ #pragma db member(object::num) deleted(3)
+ #pragma db member(object::ptr) deleted(3)
+#endif
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/drop-column/test1.hxx b/odb-tests/evolution/drop-column/test1.hxx
new file mode 100644
index 0000000..1efb1fa
--- /dev/null
+++ b/odb-tests/evolution/drop-column/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/drop-column/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/drop-column/test2.hxx b/odb-tests/evolution/drop-column/test2.hxx
new file mode 100644
index 0000000..2842cd3
--- /dev/null
+++ b/odb-tests/evolution/drop-column/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/drop-column/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/drop-column/test3.hxx b/odb-tests/evolution/drop-column/test3.hxx
new file mode 100644
index 0000000..d1ce616
--- /dev/null
+++ b/odb-tests/evolution/drop-column/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/drop-column/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/drop-foreign-key/driver.cxx b/odb-tests/evolution/drop-foreign-key/driver.cxx
new file mode 100644
index 0000000..f829562
--- /dev/null
+++ b/odb-tests/evolution/drop-foreign-key/driver.cxx
@@ -0,0 +1,145 @@
+// file : evolution/drop-foreign-key/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test dropping a foreign key.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+
+ // SQLite doesn't support dropping of foreign keys.
+ //
+#ifndef DATABASE_SQLITE
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ object o (1);
+ o.o1 = new object (2);
+ o.o2 = new object (3);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o.o1);
+ db->persist (o.o2);
+ db->persist (o);
+ t.commit ();
+ }
+
+ // The foreign key constraint is there.
+ //
+ try
+ {
+ object o (11);
+ o.o1 = new object (12);
+ o.o2 = new object (13);
+
+ transaction t (db->begin ());
+ db->persist (o);
+ assert (false);
+ }
+ catch (const odb::exception& ) {}
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ // The data is still there but the constraints are gone.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+
+ assert (p->o1 == 2);
+ assert (p->o2 == 3);
+
+ db->erase<object> (p->o1);
+ db->erase<object> (p->o2);
+
+ t.commit ();
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->o1 == 2);
+ assert (p->o2 == 3);
+ t.commit ();
+ }
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+#endif // DATABASE_SQLITE
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/drop-foreign-key/model.hxx b/odb-tests/evolution/drop-foreign-key/model.hxx
new file mode 100644
index 0000000..eed8c46
--- /dev/null
+++ b/odb-tests/evolution/drop-foreign-key/model.hxx
@@ -0,0 +1,50 @@
+// file : evolution/drop-foreign-key/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <string>
+
+#include <odb/core.hxx>
+
+#include <common/config.hxx> // DATABASE_XXX
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+ #pragma db object
+ struct object
+ {
+ #pragma db id
+ unsigned long id_;
+
+ // SQLite doesn't support dropping of foreign keys.
+ //
+#ifndef DATABASE_SQLITE
+#if MODEL_VERSION == 2
+ object* o1;
+ object* o2;
+
+ object (unsigned long id = 0): id_ (id), o1 (0), o2 (0) {}
+ ~object () {delete o1; delete o2;}
+#else
+ #pragma db null
+ unsigned long o1;
+
+ #pragma db null
+ unsigned long o2;
+
+ object (unsigned long id = 0): id_ (id) {}
+#endif
+#endif
+ };
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/drop-foreign-key/test1.hxx b/odb-tests/evolution/drop-foreign-key/test1.hxx
new file mode 100644
index 0000000..5476796
--- /dev/null
+++ b/odb-tests/evolution/drop-foreign-key/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/drop-foreign-key/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/drop-foreign-key/test2.hxx b/odb-tests/evolution/drop-foreign-key/test2.hxx
new file mode 100644
index 0000000..f091a25
--- /dev/null
+++ b/odb-tests/evolution/drop-foreign-key/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/drop-foreign-key/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/drop-foreign-key/test3.hxx b/odb-tests/evolution/drop-foreign-key/test3.hxx
new file mode 100644
index 0000000..beb8c42
--- /dev/null
+++ b/odb-tests/evolution/drop-foreign-key/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/drop-foreign-key/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/drop-index/driver.cxx b/odb-tests/evolution/drop-index/driver.cxx
new file mode 100644
index 0000000..5ad1cd4
--- /dev/null
+++ b/odb-tests/evolution/drop-index/driver.cxx
@@ -0,0 +1,154 @@
+// file : evolution/drop-index/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test dropping an index.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ object o0 (0);
+ o0.num = 123;
+
+ object o1 (1);
+ o1.num = 234;
+
+ object o2 (2);
+ o2.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o0);
+ db->persist (o1);
+ t.commit ();
+ }
+
+ // Duplicates are not ok.
+ //
+ try
+ {
+ transaction t (db->begin ());
+ db->persist (o2);
+ assert (false);
+ }
+ catch (const odb::exception& ) {}
+
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ // Duplicates are now ok.
+ //
+ object o2 (2);
+ o2.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o2);
+ t.commit ();
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p0 (db->load<object> (0));
+ auto_ptr<object> p1 (db->load<object> (1));
+ auto_ptr<object> p2 (db->load<object> (2));
+
+ assert (p0->num == 123);
+ assert (p1->num == 234);
+ assert (p2->num == 234);
+
+ t.commit ();
+ }
+
+ // Duplicates are still ok.
+ //
+ object o3 (3);
+ o3.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o3);
+ t.commit ();
+ }
+
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/drop-index/model.hxx b/odb-tests/evolution/drop-index/model.hxx
new file mode 100644
index 0000000..5e163ca
--- /dev/null
+++ b/odb-tests/evolution/drop-index/model.hxx
@@ -0,0 +1,33 @@
+// file : evolution/drop-index/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <odb/core.hxx>
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+#if MODEL_VERSION == 2
+ #pragma db unique
+#endif
+ unsigned long num;
+ };
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/drop-index/test1.hxx b/odb-tests/evolution/drop-index/test1.hxx
new file mode 100644
index 0000000..5a279bb
--- /dev/null
+++ b/odb-tests/evolution/drop-index/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/drop-index/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/drop-index/test2.hxx b/odb-tests/evolution/drop-index/test2.hxx
new file mode 100644
index 0000000..78b89f2
--- /dev/null
+++ b/odb-tests/evolution/drop-index/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/drop-index/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/drop-index/test3.hxx b/odb-tests/evolution/drop-index/test3.hxx
new file mode 100644
index 0000000..17b670d
--- /dev/null
+++ b/odb-tests/evolution/drop-index/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/drop-index/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/drop-table/driver.cxx b/odb-tests/evolution/drop-table/driver.cxx
new file mode 100644
index 0000000..81cec55
--- /dev/null
+++ b/odb-tests/evolution/drop-table/driver.cxx
@@ -0,0 +1,168 @@
+// file : evolution/drop-table/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test dropping a table (object, container).
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ {
+ using namespace v2;
+
+ object1 o1;
+ o1.o = new object (1);
+ o1.o->str = "abc";
+ o1.nums.push_back (1);
+ o1.nums.push_back (2);
+ o1.nums.push_back (3);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1.o);
+ db->persist (o1);
+ t.commit ();
+ }
+ }
+
+ // Polymorphism test.
+ //
+ {
+ // We have to use v3 here because the discriminator includes
+ // the namespace.
+ //
+ using namespace v3;
+
+ base b (123, "abc");
+ derived d1 (234, "bcd");
+ derived d2 (345, "cde");
+
+ {
+ transaction t (db->begin ());
+ db->persist (b);
+ db->persist (d1);
+ db->persist (d2);
+ t.commit ();
+ }
+ }
+
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ // Both object and object1 are still there so we can migrate the data.
+ //
+ typedef odb::query<object1> query;
+ typedef odb::result<object1> result;
+
+ {
+ transaction t (db->begin ());
+
+ result r (db->query<object1> (query::o->str == "abc"));
+ result::iterator i (r.begin ()), e (r.end ());
+
+ assert (i != e &&
+ i->o->id_ == 1 &&
+ i->nums[0] == 1 && i->nums[1] == 2 && i->nums[2] == 3);
+ assert (++i == e);
+
+ t.commit ();
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ // Only object is still there.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->str == "abc");
+ t.commit ();
+ }
+
+ // Polymorphism test.
+ //
+ {
+ transaction t (db->begin ());
+ assert (size (db->query<root> ()) == 1);
+ assert (size (db->query<base> ()) == 1);
+ t.commit ();
+ }
+
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/drop-table/model.hxx b/odb-tests/evolution/drop-table/model.hxx
new file mode 100644
index 0000000..2c02d09
--- /dev/null
+++ b/odb-tests/evolution/drop-table/model.hxx
@@ -0,0 +1,94 @@
+// file : evolution/drop-table/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <vector>
+#include <string>
+
+#include <odb/core.hxx>
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string str;
+ };
+
+ #pragma db object
+ struct object1
+ {
+ object1 (): o (0) {}
+ ~object1 () {delete o;}
+
+ #pragma db id auto
+ unsigned long id_;
+
+ object* o;
+ std::vector<int> nums;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db object(object1) deleted(3)
+#endif
+
+ // Make sure we also clean up base tables when dropping a
+ // table corresponding to the polymorphic derived object.
+ //
+ #pragma db value
+ struct value
+ {
+ value (unsigned long n = 0, const std::string& s = ""): num (n), str (s) {}
+
+ unsigned long num;
+ std::string str;
+ };
+
+ #pragma db object polymorphic
+ struct root
+ {
+ root (unsigned long n = 0, const std::string& s = ""): id (n, s) {}
+ virtual ~root () {}
+
+ #pragma db id
+ value id;
+ };
+
+ #pragma db object
+ struct base: root
+ {
+ base (unsigned long n = 0, const std::string& s = "")
+ : root (n, s), num (n) {}
+
+ unsigned long num;
+ };
+
+ #pragma db object
+ struct derived: base
+ {
+ derived (unsigned long n = 0, const std::string& s = "")
+ : base (n, s), str (s) {}
+
+ std::string str;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db object(derived) deleted(3)
+#endif
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/drop-table/test1.hxx b/odb-tests/evolution/drop-table/test1.hxx
new file mode 100644
index 0000000..a9ec64c
--- /dev/null
+++ b/odb-tests/evolution/drop-table/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/drop-table/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/drop-table/test2.hxx b/odb-tests/evolution/drop-table/test2.hxx
new file mode 100644
index 0000000..c9ec149
--- /dev/null
+++ b/odb-tests/evolution/drop-table/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/drop-table/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/drop-table/test3.hxx b/odb-tests/evolution/drop-table/test3.hxx
new file mode 100644
index 0000000..8d3f17b
--- /dev/null
+++ b/odb-tests/evolution/drop-table/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/drop-table/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/embedded/driver.cxx b/odb-tests/evolution/embedded/driver.cxx
new file mode 100644
index 0000000..1816a5c
--- /dev/null
+++ b/odb-tests/evolution/embedded/driver.cxx
@@ -0,0 +1,181 @@
+// file : evolution/embedded/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test embedded schema migration.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/config.hxx> // DATABASE_XXX
+#include <common/common.hxx>
+
+#ifdef DATABASE_PGSQL
+# include <odb/pgsql/connection.hxx>
+#endif
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ t.commit ();
+ }
+
+ // PostgreSQL cannot continue a transaction after a query failed. We
+ // have a workaround but only for 9.4+.
+ //
+#ifdef DATABASE_PGSQL
+ {
+ odb::connection_ptr c (db->connection ());
+ int v (static_cast<odb::pgsql::connection&> (*c).server_version ());
+ if (v < 90400)
+ assert (db->schema_version () == 0);
+ }
+#endif
+
+ {
+ transaction t (db->begin ());
+ assert (db->schema_version () == 0);
+
+ schema_catalog::create_schema (*db, "", false);
+
+ assert (db->schema_version () == 1 && !db->schema_migration ());
+
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ assert (db->schema_version () == 2 && !db->schema_migration ());
+
+ {
+ transaction t (db->begin ());
+ object1 o1 (1);
+ o1.num = 123;
+ db->persist (o1);
+ t.commit ();
+ }
+ break;
+ }
+ case 2:
+ {
+ using namespace v2;
+ using namespace v3;
+
+ // Check version information correctness.
+ //
+ assert (schema_catalog::base_version (*db) == 1);
+ assert (schema_catalog::current_version (*db) == 3);
+ assert (schema_catalog::next_version (*db, 0) == 3);
+ assert (schema_catalog::next_version (*db, 1) == 2);
+ assert (schema_catalog::next_version (*db) == 3);
+ assert (schema_catalog::next_version (*db, 3) == 4);
+
+ {
+ assert (db->schema_version () == 2 && !db->schema_migration ());
+
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ assert (db->schema_version () == 3 && db->schema_migration ());
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object1> o1 (db->load<object1> (1));
+ object2 o2 (1);
+ o2.num = o1->num;
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+
+ assert (db->schema_version () == 3 && !db->schema_migration ());
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ // In transaction.
+ //
+ {
+ transaction t (db->begin ());
+ assert (db->schema_version () == 3 && !db->schema_migration ());
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object2> o2 (db->load<object2> (1));
+ assert (o2->num == 123);
+ t.commit ();
+ }
+
+ // Test the case where there is still no version table.
+ //
+ db->schema_version_migration (0, false);
+
+ {
+ transaction t (db->begin ());
+
+#ifdef DATABASE_ORACLE
+ db->execute ("DROP TABLE \"schema_version\"");
+#else
+ db->execute ("DROP TABLE schema_version");
+#endif
+ t.commit ();
+ }
+
+ assert (db->schema_version () == 0);
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/embedded/model.hxx b/odb-tests/evolution/embedded/model.hxx
new file mode 100644
index 0000000..f3aa7a4
--- /dev/null
+++ b/odb-tests/evolution/embedded/model.hxx
@@ -0,0 +1,45 @@
+// file : evolution/embedded/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <odb/core.hxx>
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+#if MODEL_VERSION == 2
+ #pragma db object
+ struct object1
+ {
+ object1 (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ int num;
+ };
+#endif
+
+#if MODEL_VERSION == 3
+ #pragma db object
+ struct object2
+ {
+ object2 (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ int num;
+ };
+#endif
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/embedded/test1.hxx b/odb-tests/evolution/embedded/test1.hxx
new file mode 100644
index 0000000..32903a1
--- /dev/null
+++ b/odb-tests/evolution/embedded/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/embedded/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/embedded/test2.hxx b/odb-tests/evolution/embedded/test2.hxx
new file mode 100644
index 0000000..fce8760
--- /dev/null
+++ b/odb-tests/evolution/embedded/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/embedded/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/embedded/test3.hxx b/odb-tests/evolution/embedded/test3.hxx
new file mode 100644
index 0000000..d49ecc5
--- /dev/null
+++ b/odb-tests/evolution/embedded/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/embedded/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/soft-add/driver.cxx b/odb-tests/evolution/soft-add/driver.cxx
new file mode 100644
index 0000000..c70edcb
--- /dev/null
+++ b/odb-tests/evolution/soft-add/driver.cxx
@@ -0,0 +1,2219 @@
+// file : evolution/soft-add/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test soft-add functionality.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/config.hxx> // DATABASE_XXX
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v3; // NOTE: not v2.
+
+ if (embedded)
+ {
+ // SQLite has broken foreign keys when it comes to DDL.
+ //
+#ifdef DATABASE_SQLITE
+ db->connection ()->execute ("PRAGMA foreign_keys=OFF");
+#endif
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+
+#ifdef DATABASE_SQLITE
+ db->connection ()->execute ("PRAGMA foreign_keys=ON");
+#endif
+ }
+
+ // Test basic soft-added member logic.
+ //
+ {
+ using namespace test2;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ {
+ object o (1);
+ o.str = "abc";
+ o.num = 123;
+ o.vec.push_back (123);
+ o.ptr = new object1 (1);
+ o.ptr->ptrs.push_back (&o);
+
+ transaction t (db->begin ());
+ db->persist (o);
+ db->persist (*o.ptr);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->str == "" && p->num == 123 &&
+ p->vec.empty () && p->ptr == 0);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () &&
+ i->str == "" && i->num == 123 &&
+ i->vec.empty () && i->ptr == 0);
+
+ try
+ {
+ db->query<object> (query::str.is_null ()); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+ o.vec.push_back (234);
+ o.ptr = new object1 (2);
+ o.ptr->ptrs.push_back (&o);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ db->persist (*o.ptr);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "" && p->num == 234 &&
+ p->vec.empty () && p->ptr == 0);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+ o.vec.modify (0)++;
+ delete o.ptr;
+ o.ptr = 0;
+
+ {
+ transaction t (db->begin ());
+ db->erase<object1> (2);
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "" && p->num == 235 &&
+ p->vec.empty () && p->ptr == 0);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test empty statement handling (INSERT, UPDATE).
+ //
+ {
+ using namespace test3;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ object o;
+ o.str = "bcd";
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (o.id));
+ assert (p->str == "");
+ t.commit ();
+ }
+
+ o.str += 'e';
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (o.id));
+ assert (p->str == "");
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test empty statement handling (SELECT in polymorphic loader).
+ //
+ {
+ using namespace test4;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ object o (1);
+ o.str = "abc";
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<base> p (db->load<base> (1));
+ assert (static_cast<object&> (*p).str == "");
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test container with soft-added value member.
+ //
+ {
+ using namespace test5;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ {
+ object o (1);
+ o.vec.push_back (value ("abc", 123));
+
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->vec[0].str == "" && p->vec[0].num == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.vec.push_back (value ("bcd", 234));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->vec[0].str == "" && p->vec[0].num == 234);
+ t.commit ();
+ }
+
+ o.vec.modify (0).str += 'e';
+ o.vec.modify (0).num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->vec[0].str == "" && p->vec[0].num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test view with soft-added member.
+ //
+ {
+ using namespace test6;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ {
+ object o (1);
+ o.str = "abc";
+ o.num = 123;
+
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view> query;
+ typedef odb::result<view> result;
+
+ transaction t (db->begin ());
+ result r (db->query<view> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "" && i->num == 123);
+
+ try
+ {
+ db->query<object> (query::str == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+
+ t.commit ();
+ }
+ }
+
+ // Test soft-added section member.
+ //
+ {
+ using namespace test7;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ {
+ object o (1);
+ o.str = "abc";
+ o.num = 123;
+ o.vec.push_back (123);
+
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+
+ try
+ {
+ db->load (*p, p->s); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+ o.vec.modify (0)++;
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added members of a section.
+ //
+ {
+ using namespace test8;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ {
+ object o (1);
+ o.str = "abc";
+ o.num = 123;
+ o.vec.push_back (123);
+
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->str == "" && p->num == 123 && p->vec.empty ());
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ assert (i->str == "" && i->num == 123 && i->vec.empty ());
+
+ try
+ {
+ db->query<object> (query::str == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "" && p->num == 234 && p->vec.empty ());
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+ o.vec.modify (0)++; // No longer automatically marked as changed.
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "" && p->num == 234 && p->vec.empty ());
+ t.commit ();
+ }
+
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "" && p->num == 235 && p->vec.empty ());
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test basic soft-added member logic in polymorphic classes.
+ //
+ {
+ using namespace test9;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ {
+ object o (1);
+ o.bstr = "ab";
+ o.dstr = "abc";
+ o.num = 123;
+
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (static_cast<object*> (db->load<base> (1)));
+ assert (p->bstr == "" && p->dstr == "" && p->num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<base> query;
+ typedef odb::result<base> result;
+
+ transaction t (db->begin ());
+ result r (db->query<base> (query::id == 1));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ object& o (static_cast<object&> (*i));
+ assert (o.bstr == "" && o.dstr == "" && o.num == 123);
+
+ try
+ {
+ db->query<base> (query::bstr == "ab"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () &&
+ i->bstr == "" && i->dstr == "" && i->num);
+
+ try
+ {
+ db->query<object> (query::dstr == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+
+ t.commit ();
+ }
+
+ object o (2);
+ o.bstr = "bc";
+ o.dstr = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->bstr == "" && p->dstr == "" && p->num == 234);
+ t.commit ();
+ }
+
+ o.bstr += 'd';
+ o.dstr += 'e';
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->bstr == "" && p->dstr == "" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<base> (2);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added section member in polymorphic classes.
+ //
+ {
+ using namespace test10;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ {
+ object o (1);
+ o.bstr = "ab";
+ o.dstr = "abc";
+ o.num = 123;
+
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> p (db->load<base> (1));
+
+ try
+ {
+ db->load (*p, p->s); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+
+ t.commit ();
+ }
+
+ object o (2);
+ o.bstr = "bc";
+ o.dstr = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (static_cast<base&> (o));
+ t.commit ();
+ }
+
+ o.bstr += 'd';
+ o.dstr += 'e';
+ o.num++;
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<base&> (o));
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<base> (2);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added members of a section in polymorphic classes.
+ //
+ {
+ using namespace test11;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ {
+ object o (1);
+ o.bstr = "ab";
+ o.dstr = "abc";
+ o.num = 123;
+
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> p (db->load<base> (1));
+ db->load (*p, p->s);
+ object& o (static_cast<object&> (*p));
+ assert (o.bstr == "" && o.dstr == "" && o.num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<base> query;
+ typedef odb::result<base> result;
+
+ transaction t (db->begin ());
+ result r (db->query<base> (query::id == 1));
+ result::iterator i (r.begin ());
+ db->load (*i, i->s);
+ assert (i != r.end ());
+ object& o (static_cast<object&> (*i));
+ assert (o.bstr == "" && o.dstr == "" && o.num == 123);
+
+ try
+ {
+ db->query<base> (query::bstr == "ab"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ db->load (*i, i->s);
+ assert (i != r.end () &&
+ i->bstr == "" && i->dstr == "" && i->num);
+
+ try
+ {
+ db->query<object> (query::dstr == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+
+ t.commit ();
+ }
+
+ object o (2);
+ o.bstr = "bc";
+ o.dstr = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->bstr == "" && p->dstr == "" && p->num == 234);
+ t.commit ();
+ }
+
+ o.bstr += 'd';
+ o.dstr += 'e';
+ o.num++;
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->bstr == "" && p->dstr == "" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<base> (2);
+ t.commit ();
+ }
+
+ // Test empty statement detection in sections.
+ //
+ base b (3);
+ b.bstr = "bc";
+
+ {
+ transaction t (db->begin ());
+ db->persist (b);
+ auto_ptr<base> p (db->load<base> (3));
+ db->load (*p, p->s);
+ assert (p->bstr == "");
+ t.commit ();
+ }
+
+ b.bstr += 'd';
+ b.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (b);
+ auto_ptr<base> p (db->load<base> (3));
+ db->load (*p, p->s);
+ assert (p->bstr == "");
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (b);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added member and optimistic concurrency.
+ //
+ {
+ using namespace test12;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ {
+ object o (1);
+ o.str = "abc";
+ o.num = 123;
+
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->str == "" && p->num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "" && i->num == 123);
+
+ try
+ {
+ db->query<object> (query::str == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "" && p->num == 234);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ unsigned long long v (o.v_);
+ db->update (o);
+ assert (o.v_ != v);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "" && p->num == 235 && p->v_ == o.v_);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added member in an object without id.
+ //
+ {
+ using namespace test13;
+
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ {
+ object o;
+ o.str = "abc";
+ o.num = 123;
+
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "" && i->num == 123);
+
+ try
+ {
+ db->query<object> (query::str == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+
+ t.commit ();
+ }
+
+ object o;
+ o.str = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+
+ result r (db->query<object> (query::num == 234));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "" && i->num == 234);
+
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase_query<object> (query::num == 234);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added member in an object with auto id.
+ //
+ {
+ using namespace test14;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ unsigned long id;
+ {
+ object o;
+ o.str = "abc";
+ o.num = 123;
+
+ transaction t (db->begin ());
+ db->persist (o);
+ id = o.id;
+ t.commit ();
+ }
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (id));
+ assert (p->str == "" && p->num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "" && i->num == 123);
+
+ try
+ {
+ db->query<object> (query::str == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+
+ t.commit ();
+ }
+
+ object o;
+ o.str = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (o.id));
+ assert (p->str == "" && p->num == 234);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (o.id));
+ assert (p->str == "" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (o.id);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added container member in a non-versioned object.
+ //
+ {
+ using namespace test21;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ {
+ object o (1);
+ o.num = 123;
+ o.vec.push_back (123);
+
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->num == 123 && p->vec.empty ());
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->num == 123 && i->vec.empty ());
+ t.commit ();
+ }
+
+ object o (2);
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->num == 234 && p->vec.empty ());
+ t.commit ();
+ }
+
+ o.num++;
+ o.vec.modify (0)++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->num == 235 && p->vec.empty ());
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added container member in a non-versioned section.
+ //
+ {
+ using namespace test22;
+
+ // None of the database operations should yet include the
+ // added members.
+ //
+ {
+ object o (1);
+ o.num = 123;
+ o.vec.push_back (123);
+
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->num == 123 && p->vec.empty ());
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ assert (i->num == 123 && i->vec.empty ());
+ t.commit ();
+ }
+
+ object o (2);
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->num == 234 && p->vec.empty ());
+ t.commit ();
+ }
+
+ o.num++;
+ o.vec.modify (0)++; // No longer automatically marks as changed.
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->num == 234 && p->vec.empty ());
+ t.commit ();
+ }
+
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->num == 235 && p->vec.empty ());
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ // Test basic soft-added member logic.
+ //
+ {
+ using namespace test2;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ p->str = "abc";
+ p->vec.push_back (123);
+ delete p->ptr;
+ p->ptr = new object1 (1);
+ db->update (*p);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->str == "abc" && p->num == 123 &&
+ p->vec[0] == 123 && p->ptr->id_ == 1);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str.is_not_null () &&
+ query::ptr->id == 1));
+ result::iterator i (r.begin ());
+ assert (i != r.end () &&
+ i->str == "abc" && i->num == 123 &&
+ i->vec[0] == 123 && i->ptr->id_ == 1);
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+ o.vec.push_back (234);
+ o.ptr = new object1 (2);
+ o.ptr->ptrs.push_back (&o);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ db->persist (*o.ptr);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "bcd" && p->num == 234 &&
+ p->vec[0] == 234 && p->ptr->id_ == 2);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+ o.vec.modify (0)++;
+ delete o.ptr;
+ o.ptr = 0;
+
+ {
+ transaction t (db->begin ());
+ db->erase<object1> (2);
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "bcde" && p->num == 235 &&
+ p->vec[0] == 235 && p->ptr == 0);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test container with soft-added value member.
+ //
+ {
+ using namespace test5;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ p->vec.modify (0).str = "abc";
+ db->update (*p);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->vec[0].str == "abc" && p->vec[0].num == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.vec.push_back (value ("bcd", 234));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->vec[0].str == "bcd" && p->vec[0].num == 234);
+ t.commit ();
+ }
+
+ o.vec.modify (0).str += 'e';
+ o.vec.modify (0).num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->vec[0].str == "bcde" && p->vec[0].num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test view with soft-added member.
+ //
+ {
+ using namespace test6;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ p->str = "abc";
+ db->update (*p);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view> query;
+ typedef odb::result<view> result;
+
+ transaction t (db->begin ());
+ result r (db->query<view> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "abc" && i->num == 123);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added section member.
+ //
+ {
+ using namespace test7;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ p->str = "abc";
+ p->vec.push_back (123);
+ db->update (*p, p->s);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->str == "abc" && p->num == 123 && p->vec[0] == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ assert (i->str == "abc" && i->num == 123 && i->vec[0] == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "bcd" && p->num == 234 && p->vec[0] == 234);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+ o.vec.modify (0)++; // Automatically marks section as updated.
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "bcde" && p->num == 235 && p->vec[0] == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added members of a section.
+ //
+ {
+ using namespace test8;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ p->str = "abc";
+ p->vec.push_back (123);
+ db->update (*p, p->s);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->str == "abc" && p->num == 123 && p->vec[0] == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ assert (i->str == "abc" && i->num == 123 && i->vec[0] == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "bcd" && p->num == 234 && p->vec[0] == 234);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+ o.vec.modify (0)++; // Automatically marks section as updated.
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "bcde" && p->num == 235 && p->vec[0] == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test basic soft-added member logic in polymorphic classes.
+ //
+ {
+ using namespace test9;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ p->bstr = "ab";
+ p->dstr = "abc";
+ db->update (*p);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (static_cast<object*> (db->load<base> (1)));
+ assert (p->bstr == "ab" && p->dstr == "abc" && p->num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<base> query;
+ typedef odb::result<base> result;
+
+ transaction t (db->begin ());
+ result r (db->query<base> (query::bstr == "ab"));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ object& o (static_cast<object&> (*i));
+ assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.bstr = "bc";
+ o.dstr = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->bstr == "bc" && p->dstr == "bcd" && p->num == 234);
+ t.commit ();
+ }
+
+ o.bstr += 'd';
+ o.dstr += 'e';
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->bstr == "bcd" && p->dstr == "bcde" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (static_cast<base&> (o));
+ t.commit ();
+ }
+ }
+
+ // Test soft-added section member in polymorphic classes.
+ //
+ {
+ using namespace test10;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ p->bstr = "ab";
+ p->dstr = "abc";
+ db->update (*p, p->s);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> p (db->load<base> (1));
+ db->load (*p, p->s);
+ object& o (static_cast<object&> (*p));
+ assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<base> query;
+ typedef odb::result<base> result;
+
+ transaction t (db->begin ());
+ result r (db->query<base> (query::bstr == "ab"));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ object& o (static_cast<object&> (*i));
+ assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.bstr = "bc";
+ o.dstr = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->bstr == "bc" && p->dstr == "bcd" && p->num == 234);
+ t.commit ();
+ }
+
+ o.bstr += 'd';
+ o.dstr += 'e';
+ o.num++;
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->bstr == "bcd" && p->dstr == "bcde" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (static_cast<base&> (o));
+ t.commit ();
+ }
+ }
+
+ // Test soft-added members of a section in polymorphic classes.
+ //
+ {
+ using namespace test11;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ p->bstr = "ab";
+ p->dstr = "abc";
+ db->update (*p, p->s);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> p (db->load<base> (1));
+ db->load (*p, p->s);
+ object& o (static_cast<object&> (*p));
+ assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<base> query;
+ typedef odb::result<base> result;
+
+ transaction t (db->begin ());
+ result r (db->query<base> (query::bstr == "ab"));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ object& o (static_cast<object&> (*i));
+ assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.bstr = "bc";
+ o.dstr = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->bstr == "bc" && p->dstr == "bcd" && p->num == 234);
+ t.commit ();
+ }
+
+ o.bstr += 'd';
+ o.dstr += 'e';
+ o.num++;
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->bstr == "bcd" && p->dstr == "bcde" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (static_cast<base&> (o));
+ t.commit ();
+ }
+ }
+
+ // Test soft-added member and optimistic concurrency.
+ //
+ {
+ using namespace test12;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ p->str = "abc";
+ db->update (*p);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->str == "abc" && p->num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "abc" && i->num == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "bcd" && p->num == 234);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ unsigned long long v (o.v_);
+ db->update (o);
+ assert (o.v_ != v);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "bcde" && p->num == 235 && p->v_ == o.v_);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added member in an object without id.
+ //
+ {
+ using namespace test13;
+
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "abc" && i->num == 123);
+ t.commit ();
+ }
+
+ object o;
+ o.str = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+
+ result r (db->query<object> (query::str == "bcd"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "bcd" && i->num == 234);
+
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase_query<object> (query::str == "bcd");
+ t.commit ();
+ }
+ }
+
+ // Test soft-added member in an object with auto id.
+ //
+ {
+ using namespace test14;
+
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ unsigned long id;
+ {
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ i->str = "abc";
+ db->update (*i);
+ id = i->id;
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (id));
+ assert (p->str == "abc" && p->num == 123);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "abc" && i->num == 123);
+ t.commit ();
+ }
+
+ object o;
+ o.str = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (o.id));
+ assert (p->str == "bcd" && p->num == 234);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (o.id));
+ assert (p->str == "bcde" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added container member in a non-versioned object.
+ //
+ {
+ using namespace test21;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ p->vec.push_back (123);
+ db->update (*p);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->num == 123 && p->vec[0] == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->num == 123 && i->vec[0] == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->num == 234 && p->vec[0] == 234);
+ t.commit ();
+ }
+
+ o.num++;
+ o.vec.modify (0)++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->num == 235 && p->vec[0] == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added container member in a non-versioned section.
+ //
+ {
+ using namespace test22;
+
+ // All the database operations should now include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ p->vec.push_back (123);
+ db->update (*p, p->s);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->num == 123 && p->vec[0] == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ assert (i->num == 123 && i->vec[0] == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->num == 234 && p->vec[0] == 234);
+ t.commit ();
+ }
+
+ o.num++;
+ o.vec.modify (0)++; // Automatically marks section as changed.
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->num == 235 && p->vec[0] == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ // Test basic soft-added member logic.
+ //
+ {
+ using namespace test2;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->str == "abc" && p->num == 123 &&
+ p->vec[0] == 123 && p->ptr->id_ == 1);
+ t.commit ();
+ }
+ }
+
+ // Test container with soft-added value member.
+ //
+ {
+ using namespace test5;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->vec[0].str == "abc" && p->vec[0].num == 123);
+ t.commit ();
+ }
+ }
+
+ // Test view with soft-added member.
+ //
+ {
+ using namespace test6;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ typedef odb::query<view> query;
+ typedef odb::result<view> result;
+
+ transaction t (db->begin ());
+ result r (db->query<view> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "abc" && i->num == 123);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added section member.
+ //
+ {
+ using namespace test7;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->str == "abc" && p->num == 123 && p->vec[0] == 123);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added members of a section.
+ //
+ {
+ using namespace test8;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->str == "abc" && p->num == 123 && p->vec[0] == 123);
+ t.commit ();
+ }
+ }
+
+ // Test basic soft-added member logic in polymorphic classes.
+ //
+ {
+ using namespace test9;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (static_cast<object*> (db->load<base> (1)));
+ assert (p->bstr == "ab" && p->dstr == "abc" && p->num == 123);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added section member in polymorphic classes.
+ //
+ {
+ using namespace test10;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> p (db->load<base> (1));
+ db->load (*p, p->s);
+ object& o (static_cast<object&> (*p));
+ assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added members of a section in polymorphic classes.
+ //
+ {
+ using namespace test11;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> p (db->load<base> (1));
+ db->load (*p, p->s);
+ object& o (static_cast<object&> (*p));
+ assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added member and optimistic concurrency.
+ //
+ {
+ using namespace test12;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->str == "abc" && p->num == 123);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added member in an object without id.
+ //
+ {
+ using namespace test13;
+
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "abc" && i->num == 123);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added member in an object with auto id.
+ //
+ {
+ using namespace test14;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "abc" && i->num == 123);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added container member in a non-versioned object.
+ //
+ {
+ using namespace test21;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->num == 123 && p->vec[0] == 123);
+ t.commit ();
+ }
+ }
+
+ // Test soft-added container member in a non-versioned section.
+ //
+ {
+ using namespace test22;
+
+ // All the database operations should still include the added
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->num == 123 && p->vec[0] == 123);
+ t.commit ();
+ }
+ }
+
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/soft-add/model.hxx b/odb-tests/evolution/soft-add/model.hxx
new file mode 100644
index 0000000..39d63c4
--- /dev/null
+++ b/odb-tests/evolution/soft-add/model.hxx
@@ -0,0 +1,504 @@
+// file : evolution/soft-add/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <string>
+
+#include <odb/core.hxx>
+#include <odb/vector.hxx>
+#include <odb/section.hxx>
+#include <odb/lazy-ptr.hxx>
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+ // The test numbers are made to correspond to the soft-delete ones.
+ //
+
+ // Test basic soft-added member logic.
+ //
+ #pragma db namespace table("t2_")
+ namespace test2
+ {
+ struct object;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ odb::vector<odb::lazy_ptr<object> > ptrs;
+ };
+
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id), ptr (0) {}
+ ~object () {delete ptr;}
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string str;
+ unsigned long num;
+ odb::vector<int> vec;
+
+ #pragma db inverse(ptrs)
+ object1* ptr;
+ };
+
+#if MODEL_VERSION == 3
+ // Make it a LOB for Oracle and long data for SQL Server.
+ //
+ #pragma db member(object::str) added(3) \
+ oracle:type("CLOB") \
+ mssql:type("VARCHAR(max)")
+ #pragma db member(object::vec) added(3)
+ #pragma db member(object::ptr) added(3)
+#else
+ #pragma db member(object::str) transient
+ #pragma db member(object::vec) transient
+ #pragma db member(object::ptr) transient
+#endif
+ }
+
+ // Test empty statement handling (INSERT, UPDATE).
+ //
+ #pragma db namespace table("t3_")
+ namespace test3
+ {
+ #pragma db object
+ struct object
+ {
+ #pragma db id auto
+ unsigned long id;
+
+ std::string str;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) added(3)
+#else
+ #pragma db member(object::str) transient
+#endif
+ }
+
+ // Test empty statement handling (SELECT in polymorphic loader).
+ //
+ #pragma db namespace table("t4_")
+ namespace test4
+ {
+ #pragma db object polymorphic
+ struct base
+ {
+ virtual
+ ~base () {}
+ base (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+ };
+
+ #pragma db object
+ struct object: base
+ {
+ object (unsigned long id = 0): base (id) {}
+
+ std::string str;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) added(3)
+#else
+ #pragma db member(object::str) transient
+#endif
+ }
+
+ // Test container with soft-added value member.
+ //
+ #pragma db namespace table("t5_")
+ namespace test5
+ {
+ #pragma db value
+ struct value
+ {
+ value () {}
+ value (const std::string& s, unsigned long n): str (s), num (n) {}
+
+ std::string str;
+ unsigned long num;
+ };
+
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ odb::vector<value> vec;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(value::str) added(3)
+#else
+ #pragma db member(value::str) transient
+#endif
+ }
+
+ // Test view with soft-added member.
+ //
+ #pragma db namespace table("t6_")
+ namespace test6
+ {
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string str;
+ unsigned long num;
+ };
+
+ #pragma db view object(object)
+ struct view
+ {
+ std::string str;
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) added(3)
+ #pragma db member(view::str) added(3)
+#else
+ #pragma db member(object::str) transient
+ #pragma db member(view::str) transient
+#endif
+ }
+
+ // Test soft-added section member.
+ //
+ #pragma db namespace table("t7_")
+ namespace test7
+ {
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+#if MODEL_VERSION == 3
+ #pragma db load(lazy) update(change) added(3)
+ odb::section s;
+#endif
+
+ #pragma db section(s)
+ std::string str;
+
+ unsigned long num;
+
+ #pragma db section(s)
+ odb::vector<int> vec;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) section(s)
+ #pragma db member(object::vec) section(s)
+#else
+ #pragma db member(object::str) transient
+ #pragma db member(object::vec) transient
+#endif
+ }
+
+ // Test soft-added members of a section.
+ //
+ #pragma db namespace table("t8_")
+ namespace test8
+ {
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db load(lazy) update(change)
+ odb::section s;
+
+ std::string str;
+
+ #pragma db section(s)
+ unsigned long num;
+
+ odb::vector<int> vec;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) added(3) section(s)
+ #pragma db member(object::vec) added(3) section(s)
+#else
+ #pragma db member(object::str) transient
+ #pragma db member(object::vec) transient
+#endif
+ }
+
+ // Test basic soft-added member logic in polymorphic classes.
+ //
+ #pragma db namespace table("t9_")
+ namespace test9
+ {
+ #pragma db object polymorphic
+ struct base
+ {
+ virtual
+ ~base () {}
+ base (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string bstr;
+ };
+
+ #pragma db object
+ struct object: base
+ {
+ object (unsigned long id = 0): base (id) {}
+
+ std::string dstr;
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(base::bstr) added(3)
+ #pragma db member(object::dstr) added(3)
+#else
+ #pragma db member(base::bstr) transient
+ #pragma db member(object::dstr) transient
+#endif
+ }
+
+ // Test soft-added section member in polymorphic classes.
+ //
+ #pragma db namespace table("t10_")
+ namespace test10
+ {
+ #pragma db object polymorphic
+ struct base
+ {
+ virtual
+ ~base () {}
+ base (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+#if MODEL_VERSION == 3
+ #pragma db load(lazy) update(change) added(3)
+ odb::section s;
+#endif
+
+ std::string bstr;
+ };
+
+ #pragma db object
+ struct object: base
+ {
+ object (unsigned long id = 0): base (id) {}
+
+ std::string dstr;
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(base::bstr) section(s)
+ #pragma db member(object::dstr) section(s)
+#else
+ #pragma db member(base::bstr) transient
+ #pragma db member(object::dstr) transient
+#endif
+ }
+
+ // Test soft-added members of a section in polymorphic classes.
+ //
+ #pragma db namespace table("t11_")
+ namespace test11
+ {
+ #pragma db object polymorphic
+ struct base
+ {
+ virtual
+ ~base () {}
+ base (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db load(lazy) update(change)
+ odb::section s;
+
+ std::string bstr;
+ };
+
+ #pragma db object
+ struct object: base
+ {
+ object (unsigned long id = 0): base (id) {}
+
+ std::string dstr;
+
+ #pragma db section(s)
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(base::bstr) added(3) section(s)
+ #pragma db member(object::dstr) added(3) section(s)
+#else
+ #pragma db member(base::bstr) transient
+ #pragma db member(object::dstr) transient
+#endif
+ }
+
+ // Test soft-added member and optimistic concurrency.
+ //
+ #pragma db namespace table("t12_")
+ namespace test12
+ {
+ #pragma db object optimistic
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db version mssql:type("ROWVERSION")
+ unsigned long long v_;
+
+ std::string str;
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) added(3)
+#else
+ #pragma db member(object::str) transient
+#endif
+ }
+
+ // Test soft-added member in an object without id.
+ //
+ #pragma db namespace table("t13_")
+ namespace test13
+ {
+ #pragma db object no_id
+ struct object
+ {
+ std::string str;
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) added(3) default("abc") \
+ mysql:type("VARCHAR(255)")
+#else
+ #pragma db member(object::str) transient
+#endif
+ }
+
+ // Test soft-added member in an object with auto id.
+ //
+ #pragma db namespace table("t14_")
+ namespace test14
+ {
+ #pragma db object
+ struct object
+ {
+ std::string str;
+ unsigned long num;
+
+ #pragma db id auto
+ unsigned long id;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) added(3)
+#else
+ #pragma db member(object::str) transient
+#endif
+ }
+
+ // Test soft-added container member in a non-versioned object.
+ //
+ #pragma db namespace table("t21_")
+ namespace test21
+ {
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ unsigned long num;
+ odb::vector<int> vec;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::vec) added(3)
+#else
+ #pragma db member(object::vec) transient
+#endif
+ }
+
+ // Test soft-added container member in a non-versioned section.
+ //
+ #pragma db namespace table("t22_")
+ namespace test22
+ {
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db load(lazy) update(change)
+ odb::section s;
+
+ #pragma db section(s)
+ unsigned long num;
+
+ odb::vector<int> vec;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::vec) added(3) section(s)
+#else
+ #pragma db member(object::vec) transient
+#endif
+ }
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/soft-add/test1.hxx b/odb-tests/evolution/soft-add/test1.hxx
new file mode 100644
index 0000000..461d663
--- /dev/null
+++ b/odb-tests/evolution/soft-add/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/soft-add/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/soft-add/test2.hxx b/odb-tests/evolution/soft-add/test2.hxx
new file mode 100644
index 0000000..746da4b
--- /dev/null
+++ b/odb-tests/evolution/soft-add/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/soft-add/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/soft-add/test3.hxx b/odb-tests/evolution/soft-add/test3.hxx
new file mode 100644
index 0000000..f2990d0
--- /dev/null
+++ b/odb-tests/evolution/soft-add/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/soft-add/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/soft-delete/driver.cxx b/odb-tests/evolution/soft-delete/driver.cxx
new file mode 100644
index 0000000..e41a70c
--- /dev/null
+++ b/odb-tests/evolution/soft-delete/driver.cxx
@@ -0,0 +1,2202 @@
+// file : evolution/soft-delete/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test soft-delete functionality.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/config.hxx> // DATABASE_XXX
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ // SQLite has broken foreign keys when it comes to DDL.
+ //
+#ifdef DATABASE_SQLITE
+ db->connection ()->execute ("PRAGMA foreign_keys=OFF");
+#endif
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+
+#ifdef DATABASE_SQLITE
+ db->connection ()->execute ("PRAGMA foreign_keys=ON");
+#endif
+ }
+
+ // Test soft-deleted objects.
+ //
+ {
+ using namespace test1;
+
+ object o (1);
+ o.num = 123;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test basic soft-deleted member logic.
+ //
+ {
+ using namespace test2;
+
+ object o (1);
+ o.str = "abc";
+ o.num = 123;
+ o.vec.push_back (123);
+ o.ptr = new object1 (1);
+ o.ptr->ptrs.push_back (&o);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ db->persist (*o.ptr);
+ t.commit ();
+ }
+ }
+
+ // Test container with soft-deleted value member.
+ //
+ {
+ using namespace test5;
+
+ object o (1);
+ o.vec.push_back (value ("abc", 123));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test view with soft-deleted member.
+ //
+ {
+ using namespace test6;
+
+ object o (1);
+ o.str = "abc";
+ o.num = 123;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted section member.
+ //
+ {
+ using namespace test7;
+
+ object o (1);
+ o.str = "abc";
+ o.num = 123;
+ o.vec.push_back (123);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted members of a section.
+ //
+ {
+ using namespace test8;
+
+ object o (1);
+ o.str = "abc";
+ o.num = 123;
+ o.vec.push_back (123);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test basic soft-deleted member logic in polymorphic classes.
+ //
+ {
+ // We have to use v3 here because the discriminator includes
+ // the namespace.
+ //
+ using namespace v3::test9;
+
+ object o (1);
+ o.bstr = "ab";
+ o.dstr = "abc";
+ o.num = 123;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted section member in polymorphic classes.
+ //
+ {
+ // We have to use v3 here because the discriminator includes
+ // the namespace.
+ //
+ using namespace v3::test10;
+
+ object o (1);
+ o.bstr = "ab";
+ o.dstr = "abc";
+ o.num = 123;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted members of a section in polymorphic classes.
+ //
+ {
+ // We have to use v3 here because the discriminator includes
+ // the namespace.
+ //
+ using namespace v3::test11;
+
+ object o (1);
+ o.bstr = "ab";
+ o.dstr = "abc";
+ o.num = 123;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted member and optimistic concurrency.
+ //
+ {
+ using namespace test12;
+
+ object o (1);
+ o.str = "abc";
+ o.num = 123;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted member in an object without id.
+ //
+ {
+ using namespace test13;
+
+ object o;
+ o.str = "abc";
+ o.num = 123;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted member in an object with auto id.
+ //
+ {
+ using namespace test14;
+
+ object o;
+ o.str = "abc";
+ o.num = 123;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test summarily deleted composite values.
+ //
+ {
+ using namespace test15;
+
+ object o (1);
+ o.v.reset (new value);
+ o.v->str = "abc";
+ o.v->vec.push_back (123);
+ o.num = 123;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted container member in a non-versioned object.
+ //
+ {
+ using namespace test21;
+
+ object o (1);
+ o.num = 123;
+ o.vec.push_back (123);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted container member in a non-versioned section.
+ //
+ {
+ using namespace test22;
+
+ object o (1);
+ o.num = 123;
+ o.vec.push_back (123);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+ }
+
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ // Test soft-deleted objects.
+ //
+ {
+ using namespace test1;
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->num == 123);
+ t.commit ();
+ }
+ }
+
+ // Test basic soft-deleted member logic.
+ //
+ {
+ using namespace test2;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->str == "abc" && p->num == 123 &&
+ p->vec[0] == 123 && p->ptr->id_ == 1);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc" &&
+ query::ptr->id == 1));
+ result::iterator i (r.begin ());
+ assert (i != r.end () &&
+ i->str == "abc" && i->num == 123 &&
+ i->vec[0] == 123 && i->ptr->id_ == 1);
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+ o.vec.push_back (234);
+ o.ptr = new object1 (2);
+ o.ptr->ptrs.push_back (&o);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ db->persist (*o.ptr);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "bcd" && p->num == 234 &&
+ p->vec[0] == 234 && p->ptr->id_ == 2);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+ o.vec.modify (0)++;
+ delete o.ptr;
+ o.ptr = 0;
+
+ {
+ transaction t (db->begin ());
+ db->erase<object1> (2);
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "bcde" && p->num == 235 &&
+ p->vec[0] == 235 && p->ptr == 0);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test container with soft-deleted value member.
+ //
+ {
+ using namespace test5;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->vec[0].str == "abc" && p->vec[0].num == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.vec.push_back (value ("bcd", 234));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->vec[0].str == "bcd" && p->vec[0].num == 234);
+ t.commit ();
+ }
+
+ o.vec.modify (0).str += 'e';
+ o.vec.modify (0).num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->vec[0].str == "bcde" && p->vec[0].num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test view with soft-deleted member.
+ //
+ {
+ using namespace test6;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ typedef odb::query<view> query;
+ typedef odb::result<view> result;
+
+ transaction t (db->begin ());
+ result r (db->query<view> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "abc" && i->num == 123);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted section member.
+ //
+ {
+ using namespace test7;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->str == "abc" && p->num == 123 && p->vec[0] == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ assert (i->str == "abc" && i->num == 123 && i->vec[0] == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "bcd" && p->num == 234 && p->vec[0] == 234);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+ o.vec.modify (0)++; // Automatically marks section as updated.
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "bcde" && p->num == 235 && p->vec[0] == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted members of a section.
+ //
+ {
+ using namespace test8;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->str == "abc" && p->num == 123 && p->vec[0] == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ assert (i->str == "abc" && i->num == 123 && i->vec[0] == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "bcd" && p->num == 234 && p->vec[0] == 234);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+ o.vec.modify (0)++; // Automatically marks section as updated.
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "bcde" && p->num == 235 && p->vec[0] == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test basic soft-deleted member logic in polymorphic classes.
+ //
+ {
+ using namespace test9;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (static_cast<object*> (db->load<base> (1)));
+ assert (p->bstr == "ab" && p->dstr == "abc" && p->num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<base> query;
+ typedef odb::result<base> result;
+
+ transaction t (db->begin ());
+ result r (db->query<base> (query::bstr == "ab"));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ object& o (static_cast<object&> (*i));
+ assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.bstr = "bc";
+ o.dstr = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->bstr == "bc" && p->dstr == "bcd" && p->num == 234);
+ t.commit ();
+ }
+
+ o.bstr += 'd';
+ o.dstr += 'e';
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->bstr == "bcd" && p->dstr == "bcde" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (static_cast<base&> (o));
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted section member in polymorphic classes.
+ //
+ {
+ using namespace test10;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> p (db->load<base> (1));
+ db->load (*p, p->s);
+ object& o (static_cast<object&> (*p));
+ assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<base> query;
+ typedef odb::result<base> result;
+
+ transaction t (db->begin ());
+ result r (db->query<base> (query::bstr == "ab"));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ object& o (static_cast<object&> (*i));
+ assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.bstr = "bc";
+ o.dstr = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->bstr == "bc" && p->dstr == "bcd" && p->num == 234);
+ t.commit ();
+ }
+
+ o.bstr += 'd';
+ o.dstr += 'e';
+ o.num++;
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->bstr == "bcd" && p->dstr == "bcde" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (static_cast<base&> (o));
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted members of a section in polymorphic classes.
+ //
+ {
+ using namespace test11;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> p (db->load<base> (1));
+ db->load (*p, p->s);
+ object& o (static_cast<object&> (*p));
+ assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<base> query;
+ typedef odb::result<base> result;
+
+ transaction t (db->begin ());
+ result r (db->query<base> (query::bstr == "ab"));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ object& o (static_cast<object&> (*i));
+ assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.bstr = "bc";
+ o.dstr = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->bstr == "bc" && p->dstr == "bcd" && p->num == 234);
+ t.commit ();
+ }
+
+ o.bstr += 'd';
+ o.dstr += 'e';
+ o.num++;
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->bstr == "bcd" && p->dstr == "bcde" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (static_cast<base&> (o));
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted member and optimistic concurrency.
+ //
+ {
+ using namespace test12;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->str == "abc" && p->num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "abc" && i->num == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "bcd" && p->num == 234);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ unsigned long long v (o.v_);
+ db->update (o);
+ assert (o.v_ != v);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "bcde" && p->num == 235 && p->v_ == o.v_);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted member in an object without id.
+ //
+ {
+ using namespace test13;
+
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "abc" && i->num == 123);
+ t.commit ();
+ }
+
+ object o;
+ o.str = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+
+ result r (db->query<object> (query::str == "bcd"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "bcd" && i->num == 234);
+
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase_query<object> (query::str == "bcd");
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted member in an object with auto id.
+ //
+ {
+ using namespace test14;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ unsigned long id;
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "abc" && i->num == 123);
+ id = i->id;
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (id));
+ assert (p->str == "abc" && p->num == 123);
+ t.commit ();
+ }
+
+ object o;
+ o.str = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (o.id));
+ assert (p->str == "bcd" && p->num == 234);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (o.id));
+ assert (p->str == "bcde" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test summarily deleted composite values.
+ //
+ {
+ using namespace test15;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->v->str == "abc" && p->num == 123 &&
+ p->v->vec[0] == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::v.str == "abc"));
+ result::iterator i (r.begin ());
+ assert (i != r.end () &&
+ i->v->str == "abc" && i->num == 123 &&
+ i->v->vec[0] == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.v.reset (new value);
+ o.v->str = "bcd";
+ o.num = 234;
+ o.v->vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->v->str == "bcd" && p->num == 234 &&
+ p->v->vec[0] == 234);
+ t.commit ();
+ }
+
+ o.v->str += 'e';
+ o.num++;
+ o.v->vec.modify (0)++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->v->str == "bcde" && p->num == 235 &&
+ p->v->vec[0] == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted container member in a non-versioned object.
+ //
+ {
+ using namespace test21;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->num == 123 && p->vec[0] == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->num == 123 && i->vec[0] == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->num == 234 && p->vec[0] == 234);
+ t.commit ();
+ }
+
+ o.num++;
+ o.vec.modify (0)++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->num == 235 && p->vec[0] == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted container member in a non-versioned section.
+ //
+ {
+ using namespace test22;
+
+ // All the database operations should still include the deleted
+ // members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->num == 123 && p->vec[0] == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ assert (i->num == 123 && i->vec[0] == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->num == 234 && p->vec[0] == 234);
+ t.commit ();
+ }
+
+ o.num++;
+ o.vec.modify (0)++; // Automatically marks section as changed.
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->num == 235 && p->vec[0] == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (o);
+ t.commit ();
+ }
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ // Test soft-deleted objects.
+ //
+ {
+ using namespace test1;
+
+ try
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1)); // No such table.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+ }
+
+ // Test basic soft-deleted member logic.
+ //
+ {
+ using namespace test2;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->str == "" && p->num == 123 &&
+ p->vec.empty () && p->ptr == 0);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () &&
+ i->str == "" && i->num == 123 &&
+ i->vec.empty () && i->ptr == 0);
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->query<object> (query::str == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#else
+ assert (size (db->query<object> (query::str.is_null ())) == 1);
+#endif
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+ o.vec.push_back (234);
+ o.ptr = new object1 (2);
+ o.ptr->ptrs.push_back (&o);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ db->persist (*o.ptr);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "" && p->num == 234 &&
+ p->vec.empty () && p->ptr == 0);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+ o.vec.modify (0)++;
+ delete o.ptr;
+ o.ptr = 0;
+
+ {
+ transaction t (db->begin ());
+ db->erase<object1> (2);
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "" && p->num == 235 &&
+ p->vec.empty () && p->ptr == 0);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test empty statement handling (INSERT, UPDATE).
+ //
+ {
+ using namespace test3;
+
+ // Now none of the database operations should include the
+ // deleted member.
+ //
+ object o;
+ o.str = "bcd";
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (o.id));
+ assert (p->str == "");
+ t.commit ();
+ }
+
+ o.str += 'e';
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (o.id));
+ assert (p->str == "");
+ t.commit ();
+ }
+ }
+
+ // Test empty statement handling (SELECT in polymorphic loader).
+ //
+ {
+ using namespace test4;
+
+ // Now none of the database operations should include the
+ // deleted member.
+ //
+ object o (1);
+ o.str = "abc";
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<base> p (db->load<base> (1));
+ assert (static_cast<object&> (*p).str == "");
+ t.commit ();
+ }
+ }
+
+ // Test container with soft-deleted value member.
+ //
+ {
+ using namespace test5;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->vec[0].str == "" && p->vec[0].num == 123);
+ t.commit ();
+ }
+
+ object o (2);
+ o.vec.push_back (value ("bcd", 234));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->vec[0].str == "" && p->vec[0].num == 234);
+ t.commit ();
+ }
+
+ o.vec.modify (0).str += 'e';
+ o.vec.modify (0).num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->vec[0].str == "" && p->vec[0].num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test view with soft-deleted member.
+ //
+ {
+ using namespace test6;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ typedef odb::query<view> query;
+ typedef odb::result<view> result;
+
+ transaction t (db->begin ());
+ result r (db->query<view> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "" && i->num == 123);
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->query<object> (query::str == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#else
+ assert (size (db->query<object> (query::str.is_null ())) == 1);
+#endif
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted section member.
+ //
+ {
+ using namespace test7;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->load (*p, p->s); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#endif
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+ o.vec.modify (0)++;
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted members of a section.
+ //
+ {
+ using namespace test8;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->str == "" && p->num == 123 && p->vec.empty ());
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ assert (i->str == "" && i->num == 123 && i->vec.empty ());
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->query<object> (query::str == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#else
+ assert (size (db->query<object> (query::str.is_null ())) == 1);
+#endif
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "" && p->num == 234 && p->vec.empty ());
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+ o.vec.modify (0)++; // No longer automatically marked as changed.
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "" && p->num == 234 && p->vec.empty ());
+ t.commit ();
+ }
+
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->str == "" && p->num == 235 && p->vec.empty ());
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test basic soft-deleted member logic in polymorphic classes.
+ //
+ {
+ using namespace test9;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (static_cast<object*> (db->load<base> (1)));
+ assert (p->bstr == "" && p->dstr == "" && p->num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<base> query;
+ typedef odb::result<base> result;
+
+ transaction t (db->begin ());
+ result r (db->query<base> (query::id == 1));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ object& o (static_cast<object&> (*i));
+ assert (o.bstr == "" && o.dstr == "" && o.num == 123);
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->query<base> (query::bstr == "ab"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#else
+ assert (size (db->query<base> (query::bstr.is_null ())) == 1);
+#endif
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () &&
+ i->bstr == "" && i->dstr == "" && i->num);
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->query<object> (query::dstr == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#else
+ assert (size (db->query<object> (query::dstr.is_null ())) == 1);
+#endif
+ t.commit ();
+ }
+
+ object o (2);
+ o.bstr = "bc";
+ o.dstr = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->bstr == "" && p->dstr == "" && p->num == 234);
+ t.commit ();
+ }
+
+ o.bstr += 'd';
+ o.dstr += 'e';
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->bstr == "" && p->dstr == "" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<base> (2);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted section member in polymorphic classes.
+ //
+ {
+ using namespace test10;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> p (db->load<base> (1));
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->load (*p, p->s); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#endif
+ t.commit ();
+ }
+
+ object o (2);
+ o.bstr = "bc";
+ o.dstr = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (static_cast<base&> (o));
+ t.commit ();
+ }
+
+ o.bstr += 'd';
+ o.dstr += 'e';
+ o.num++;
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<base&> (o));
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<base> (2);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted members of a section in polymorphic classes.
+ //
+ {
+ using namespace test11;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> p (db->load<base> (1));
+ db->load (*p, p->s);
+ object& o (static_cast<object&> (*p));
+ assert (o.bstr == "" && o.dstr == "" && o.num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<base> query;
+ typedef odb::result<base> result;
+
+ transaction t (db->begin ());
+ result r (db->query<base> (query::id == 1));
+ result::iterator i (r.begin ());
+ db->load (*i, i->s);
+ assert (i != r.end ());
+ object& o (static_cast<object&> (*i));
+ assert (o.bstr == "" && o.dstr == "" && o.num == 123);
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->query<base> (query::bstr == "ab"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#else
+ assert (size (db->query<base> (query::bstr.is_null ())) == 1);
+#endif
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ db->load (*i, i->s);
+ assert (i != r.end () &&
+ i->bstr == "" && i->dstr == "" && i->num);
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->query<object> (query::dstr == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#else
+ assert (size (db->query<object> (query::dstr.is_null ())) == 1);
+#endif
+ t.commit ();
+ }
+
+ object o (2);
+ o.bstr = "bc";
+ o.dstr = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->bstr == "" && p->dstr == "" && p->num == 234);
+ t.commit ();
+ }
+
+ o.bstr += 'd';
+ o.dstr += 'e';
+ o.num++;
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<base&> (o));
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->bstr == "" && p->dstr == "" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<base> (2);
+ t.commit ();
+ }
+
+ // Test empty statement detection in sections.
+ //
+ base b (3);
+ b.bstr = "bc";
+
+ {
+ transaction t (db->begin ());
+ db->persist (b);
+ auto_ptr<base> p (db->load<base> (3));
+ db->load (*p, p->s);
+ assert (p->bstr == "");
+ t.commit ();
+ }
+
+ b.bstr += 'd';
+ b.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (b);
+ auto_ptr<base> p (db->load<base> (3));
+ db->load (*p, p->s);
+ assert (p->bstr == "");
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted member and optimistic concurrency.
+ //
+ {
+ using namespace test12;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->str == "" && p->num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "" && i->num == 123);
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->query<object> (query::str == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#else
+ assert (size (db->query<object> (query::str.is_null ())) == 1);
+#endif
+ t.commit ();
+ }
+
+ object o (2);
+ o.str = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "" && p->num == 234);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ unsigned long long v (o.v_);
+ db->update (o);
+ assert (o.v_ != v);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->str == "" && p->num == 235 && p->v_ == o.v_);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted member in an object without id.
+ //
+ {
+ using namespace test13;
+
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "" && i->num == 123);
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->query<object> (query::str == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#else
+ assert (size (db->query<object> (query::str.is_null ())) == 1);
+#endif
+ t.commit ();
+ }
+
+ object o;
+ o.str = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+
+ result r (db->query<object> (query::num == 234));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "" && i->num == 234);
+
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase_query<object> (query::num == 234);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted member in an object with auto id.
+ //
+ {
+ using namespace test14;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ unsigned long id;
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->str == "" && i->num == 123);
+ id = i->id;
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->query<object> (query::str == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#else
+ assert (size (db->query<object> (query::str.is_null ())) == 1);
+#endif
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (id));
+ assert (p->str == "" && p->num == 123);
+ t.commit ();
+ }
+
+ object o;
+ o.str = "bcd";
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (o.id));
+ assert (p->str == "" && p->num == 234);
+ t.commit ();
+ }
+
+ o.str += 'e';
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (o.id));
+ assert (p->str == "" && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (o.id);
+ t.commit ();
+ }
+ }
+
+ // Test summarily deleted composite values.
+ //
+ {
+ using namespace test15;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->v.get () == 0 && p->num == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->v.get () == 0 && i->num == 123);
+
+ // Logical delete in SQLite.
+ //
+#ifndef DATABASE_SQLITE
+ try
+ {
+ db->query<object> (query::v.str == "abc"); // No such column.
+ assert (false);
+ }
+ catch (const odb::exception&) {}
+#else
+ assert (size (db->query<object> (query::v.str.is_null ())) == 1);
+#endif
+ t.commit ();
+ }
+
+ object o (2);
+ o.num = 234;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->v.get () == 0 && p->num == 234);
+ t.commit ();
+ }
+
+ o.num++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->v.get () == 0 && p->num == 235);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted container member in a non-versioned object.
+ //
+ {
+ using namespace test21;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ assert (p->num == 123 && p->vec.empty ());
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end () && i->num == 123 && i->vec.empty ());
+ t.commit ();
+ }
+
+ object o (2);
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->num == 234 && p->vec.empty ());
+ t.commit ();
+ }
+
+ o.num++;
+ o.vec.modify (0)++;
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ assert (p->num == 235 && p->vec.empty ());
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ // Test soft-deleted container member in a non-versioned section.
+ //
+ {
+ using namespace test22;
+
+ // Now none of the database operations should include the
+ // deleted members.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (1));
+ db->load (*p, p->s);
+ assert (p->num == 123 && p->vec.empty ());
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<object> query;
+ typedef odb::result<object> result;
+
+ transaction t (db->begin ());
+ result r (db->query<object> (query::num == 123));
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+ db->load (*i, i->s);
+ assert (i->num == 123 && i->vec.empty ());
+ t.commit ();
+ }
+
+ object o (2);
+ o.num = 234;
+ o.vec.push_back (234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->num == 234 && p->vec.empty ());
+ t.commit ();
+ }
+
+ o.num++;
+ o.vec.modify (0)++; // No longer automatically marks as changed.
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->num == 234 && p->vec.empty ());
+ t.commit ();
+ }
+
+ o.s.change ();
+
+ {
+ transaction t (db->begin ());
+ db->update (o);
+ auto_ptr<object> p (db->load<object> (2));
+ db->load (*p, p->s);
+ assert (p->num == 235 && p->vec.empty ());
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase<object> (2);
+ t.commit ();
+ }
+ }
+
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/soft-delete/model.hxx b/odb-tests/evolution/soft-delete/model.hxx
new file mode 100644
index 0000000..65083dd
--- /dev/null
+++ b/odb-tests/evolution/soft-delete/model.hxx
@@ -0,0 +1,518 @@
+// file : evolution/soft-delete/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <common/config.hxx> // HAVE_CXX11
+
+#include <string>
+#include <memory> // std::auto_ptr/unique_ptr
+
+#include <odb/core.hxx>
+#include <odb/vector.hxx>
+#include <odb/section.hxx>
+#include <odb/lazy-ptr.hxx>
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+ // Test soft-deleted objects.
+ //
+ #pragma db namespace table("t1_")
+ namespace test1
+ {
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db object(object) deleted(3)
+#endif
+ }
+
+ // Test basic soft-deleted member logic.
+ //
+ #pragma db namespace table("t2_")
+ namespace test2
+ {
+ struct object;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ odb::vector<odb::lazy_ptr<object> > ptrs;
+ };
+
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id), ptr (0) {}
+ ~object () {delete ptr;}
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string str;
+ unsigned long num;
+ odb::vector<int> vec;
+
+ #pragma db inverse(ptrs)
+ object1* ptr;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) deleted(3)
+ #pragma db member(object::vec) deleted(3)
+ #pragma db member(object::ptr) deleted(3)
+#endif
+ }
+
+ // Test empty statement handling (INSERT, UPDATE).
+ //
+ #pragma db namespace table("t3_")
+ namespace test3
+ {
+ #pragma db object
+ struct object
+ {
+ #pragma db id auto
+ unsigned long id;
+
+ std::string str;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) deleted(3)
+#endif
+ }
+
+ // Test empty statement handling (SELECT in polymorphic loader).
+ //
+ #pragma db namespace table("t4_")
+ namespace test4
+ {
+ #pragma db object polymorphic
+ struct base
+ {
+ virtual
+ ~base () {}
+ base (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+ };
+
+ #pragma db object
+ struct object: base
+ {
+ object (unsigned long id = 0): base (id) {}
+
+ std::string str;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) deleted(3)
+#endif
+ }
+
+ // Test container with soft-deleted value member.
+ //
+ #pragma db namespace table("t5_")
+ namespace test5
+ {
+ #pragma db value
+ struct value
+ {
+ value () {}
+ value (const std::string& s, unsigned long n): str (s), num (n) {}
+
+ std::string str;
+ unsigned long num;
+ };
+
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ odb::vector<value> vec;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(value::str) deleted(3)
+#endif
+ }
+
+ // Test view with soft-deleted member.
+ //
+ #pragma db namespace table("t6_")
+ namespace test6
+ {
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string str;
+ unsigned long num;
+ };
+
+ #pragma db view object(object)
+ struct view
+ {
+ std::string str;
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) deleted(3)
+ #pragma db member(view::str) deleted(3)
+#endif
+ }
+
+ // Test soft-deleted section member.
+ //
+ #pragma db namespace table("t7_")
+ namespace test7
+ {
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db load(lazy) update(change)
+ odb::section s;
+
+ #pragma db section(s)
+ std::string str;
+
+ unsigned long num;
+
+ #pragma db section(s)
+ odb::vector<int> vec;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::s) deleted(3)
+#endif
+ }
+
+ // Test soft-deleted members of a section.
+ //
+ #pragma db namespace table("t8_")
+ namespace test8
+ {
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db load(lazy) update(change)
+ odb::section s;
+
+ #pragma db section(s)
+ std::string str;
+
+ #pragma db section(s)
+ unsigned long num;
+
+ #pragma db section(s)
+ odb::vector<int> vec;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) deleted(3)
+ #pragma db member(object::vec) deleted(3)
+#endif
+ }
+
+ // Test basic soft-deleted member logic in polymorphic classes.
+ //
+ #pragma db namespace table("t9_")
+ namespace test9
+ {
+ #pragma db object polymorphic
+ struct base
+ {
+ virtual
+ ~base () {}
+ base (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string bstr;
+ };
+
+ #pragma db object
+ struct object: base
+ {
+ object (unsigned long id = 0): base (id) {}
+
+ std::string dstr;
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(base::bstr) deleted(3)
+ #pragma db member(object::dstr) deleted(3)
+#endif
+ }
+
+ // Test soft-deleted section member in polymorphic classes.
+ //
+ #pragma db namespace table("t10_")
+ namespace test10
+ {
+ #pragma db object polymorphic
+ struct base
+ {
+ virtual
+ ~base () {}
+ base (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db load(lazy) update(change)
+ odb::section s;
+
+ #pragma db section(s)
+ std::string bstr;
+ };
+
+ #pragma db object
+ struct object: base
+ {
+ object (unsigned long id = 0): base (id) {}
+
+ #pragma db section(s)
+ std::string dstr;
+
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(base::s) deleted(3)
+#endif
+ }
+
+ // Test soft-deleted members of a section in polymorphic classes.
+ //
+ #pragma db namespace table("t11_")
+ namespace test11
+ {
+ #pragma db object polymorphic
+ struct base
+ {
+ virtual
+ ~base () {}
+ base (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db load(lazy) update(change)
+ odb::section s;
+
+ #pragma db section(s)
+ std::string bstr;
+ };
+
+ #pragma db object
+ struct object: base
+ {
+ object (unsigned long id = 0): base (id) {}
+
+ #pragma db section(s)
+ std::string dstr;
+
+ #pragma db section(s)
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(base::bstr) deleted(3)
+ #pragma db member(object::dstr) deleted(3)
+#endif
+ }
+
+ // Test soft-deleted member and optimistic concurrency.
+ //
+ #pragma db namespace table("t12_")
+ namespace test12
+ {
+ #pragma db object optimistic
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db version mssql:type("ROWVERSION")
+ unsigned long long v_;
+
+ std::string str;
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) deleted(3)
+#endif
+ }
+
+ // Test soft-deleted member in an object without id.
+ //
+ #pragma db namespace table("t13_")
+ namespace test13
+ {
+ #pragma db object no_id
+ struct object
+ {
+ std::string str;
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) deleted(3)
+#endif
+ }
+
+ // Test soft-deleted member in an object with auto id.
+ //
+ #pragma db namespace table("t14_")
+ namespace test14
+ {
+ #pragma db object
+ struct object
+ {
+ std::string str;
+ unsigned long num;
+
+ #pragma db id auto
+ unsigned long id;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::str) deleted(3)
+#endif
+ }
+
+ // Test summarily deleted composite values.
+ //
+ #pragma db namespace table("t15_")
+ namespace test15
+ {
+ #pragma db value
+ struct value
+ {
+ std::string str;
+ odb::vector<int> vec;
+ };
+
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+#ifdef HAVE_CXX11
+ std::unique_ptr<value> v;
+#else
+ std::auto_ptr<value> v;
+#endif
+ unsigned long num;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(value::str) deleted(3)
+ #pragma db member(value::vec) deleted(3)
+#endif
+ }
+
+ // Test soft-deleted container member in a non-versioned object.
+ //
+ #pragma db namespace table("t21_")
+ namespace test21
+ {
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ unsigned long num;
+ odb::vector<int> vec;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::vec) deleted(3)
+#endif
+ }
+
+ // Test soft-deleted container member in a non-versioned section.
+ //
+ #pragma db namespace table("t22_")
+ namespace test22
+ {
+ #pragma db object
+ struct object
+ {
+ object (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db load(lazy) update(change)
+ odb::section s;
+
+ #pragma db section(s)
+ unsigned long num;
+
+ #pragma db section(s)
+ odb::vector<int> vec;
+ };
+
+#if MODEL_VERSION == 3
+ #pragma db member(object::vec) deleted(3)
+#endif
+ }
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/soft-delete/test1.hxx b/odb-tests/evolution/soft-delete/test1.hxx
new file mode 100644
index 0000000..d4df90f
--- /dev/null
+++ b/odb-tests/evolution/soft-delete/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/soft-delete/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/soft-delete/test2.hxx b/odb-tests/evolution/soft-delete/test2.hxx
new file mode 100644
index 0000000..3b2b5b4
--- /dev/null
+++ b/odb-tests/evolution/soft-delete/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/soft-delete/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/soft-delete/test3.hxx b/odb-tests/evolution/soft-delete/test3.hxx
new file mode 100644
index 0000000..5a90ab2
--- /dev/null
+++ b/odb-tests/evolution/soft-delete/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/soft-delete/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/template/driver.cxx b/odb-tests/evolution/template/driver.cxx
new file mode 100644
index 0000000..b278acd
--- /dev/null
+++ b/odb-tests/evolution/template/driver.cxx
@@ -0,0 +1,124 @@
+// file : evolution/template/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// PLACE TEST DESCRIPTION HERE
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+ schema_catalog::create_schema (*db, "", false);
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ dummy d (1);
+ db->persist (d);
+ t.commit ();
+ }
+ break;
+ }
+ case 2:
+ {
+ using namespace v3;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<dummy> p (db->load<dummy> (1));
+ t.commit ();
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ object o;
+
+ {
+ transaction t (db->begin ());
+ db->persist (o);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object> p (db->load<object> (o.id_));
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<dummy> p (db->load<dummy> (1));
+ t.commit ();
+ }
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/template/model.hxx b/odb-tests/evolution/template/model.hxx
new file mode 100644
index 0000000..182c81f
--- /dev/null
+++ b/odb-tests/evolution/template/model.hxx
@@ -0,0 +1,40 @@
+// file : evolution/template/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <odb/core.hxx>
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+#if MODEL_VERSION == 3
+ #pragma db object
+ struct object
+ {
+ #pragma db id auto
+ unsigned long id_;
+ };
+#endif
+
+ // The presence of this object makes sure that there are no empty
+ // changesets and we get the complete set of migration files.
+ //
+ #pragma db object
+ struct dummy
+ {
+ dummy (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+ };
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/template/template-vc10.vcxproj b/odb-tests/evolution/template/template-vc10.vcxproj
new file mode 100644
index 0000000..c0ebe18
--- /dev/null
+++ b/odb-tests/evolution/template/template-vc10.vcxproj
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{__uuid__()}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>__value__(name)</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(Configuration)\</OutDir>
+ <TargetName>driver</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(Platform)\$(Configuration)\</OutDir>
+ <TargetName>driver</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(Configuration)\</OutDir>
+ <TargetName>driver</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(Platform)\$(Configuration)\</OutDir>
+ <TargetName>driver</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)\..\libcommon</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4068;4355;4800;4290;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(SolutionDir)\..\libcommon\lib\common-d.lib;odb-__value__(database)-d.lib;odb-d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)\..\libcommon</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4068;4355;4800;4290;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(SolutionDir)\..\libcommon\lib64\common-d.lib;odb-__value__(database)-d.lib;odb-d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)\..\libcommon</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4068;4355;4800;4290;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(SolutionDir)\..\libcommon\lib\common.lib;odb-__value__(database).lib;odb.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)\..\libcommon</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4068;4355;4800;4290;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(SolutionDir)\..\libcommon\lib64\common.lib;odb-__value__(database).lib;odb.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+__custom_build_entry__(
+test1.hxx,
+odb test1.hxx,
+odb.exe --std c++11 --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options1) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1600 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test1.hxx,
+test1-odb.hxx;test1-odb.ixx;test1-odb.cxx;test1.sql;model.xml,
+model.hxx)
+__custom_build_entry__(
+test2.hxx,
+odb test2.hxx,
+odb.exe --std c++11 --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options2) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1600 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test2.hxx,
+test2-odb.hxx;test2-odb.ixx;test2-odb.cxx;test2.sql;model.xml,
+test1-odb.hxx;model.hxx)
+__custom_build_entry__(
+test3.hxx,
+odb test3.hxx,
+odb.exe --std c++11 --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options3) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1600 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test3.hxx,
+test3-odb.hxx;test3-odb.ixx;test3-odb.cxx;test3.sql;test3-002-pre.sql;test3-002-post.sql;test3-003-pre.sql;test3-003-post.sql,
+test2-odb.hxx;model.hxx)
+ </ItemGroup>
+ <ItemGroup>
+__header_entry__(test1-odb.hxx)
+__header_entry__(test1-odb.ixx)
+__header_entry__(test2-odb.hxx)
+__header_entry__(test2-odb.ixx)
+__header_entry__(test3-odb.hxx)
+__header_entry__(test3-odb.ixx)
+__header_entries__(extra_headers)
+ </ItemGroup>
+ <ItemGroup>
+__source_entry__(driver.cxx)
+__source_entry__(test1-odb.cxx)
+__source_entry__(test2-odb.cxx)
+__source_entry__(test3-odb.cxx)
+__source_entries__(extra_sources)
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/odb-tests/evolution/template/template-vc10.vcxproj.filters b/odb-tests/evolution/template/template-vc10.vcxproj.filters
new file mode 100644
index 0000000..d6ac66e
--- /dev/null
+++ b/odb-tests/evolution/template/template-vc10.vcxproj.filters
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{__uuid__()}</UniqueIdentifier>
+ <Extensions>cxx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{__uuid__()}</UniqueIdentifier>
+ <Extensions>h;hxx;ixx;txx</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+__header_filter_entry__(test1.hxx)
+__header_filter_entry__(test1-odb.hxx)
+__header_filter_entry__(test1-odb.ixx)
+__header_filter_entry__(test2.hxx)
+__header_filter_entry__(test2-odb.hxx)
+__header_filter_entry__(test2-odb.ixx)
+__header_filter_entry__(test3.hxx)
+__header_filter_entry__(test3-odb.hxx)
+__header_filter_entry__(test3-odb.ixx)
+__header_filter_entries__(extra_headers)
+ </ItemGroup>
+ <ItemGroup>
+__source_filter_entry__(driver.cxx)
+__source_filter_entry__(test1-odb.cxx)
+__source_filter_entry__(test2-odb.cxx)
+__source_filter_entry__(test3-odb.cxx)
+__source_filter_entries__(extra_sources)
+ </ItemGroup>
+</Project>
diff --git a/odb-tests/evolution/template/template-vc11.vcxproj b/odb-tests/evolution/template/template-vc11.vcxproj
new file mode 100644
index 0000000..f51fd0c
--- /dev/null
+++ b/odb-tests/evolution/template/template-vc11.vcxproj
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{__uuid__()}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>__value__(name)</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v110</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v110</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v110</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v110</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(Configuration)\</OutDir>
+ <TargetName>driver</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(Platform)\$(Configuration)\</OutDir>
+ <TargetName>driver</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(Configuration)\</OutDir>
+ <TargetName>driver</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(Platform)\$(Configuration)\</OutDir>
+ <TargetName>driver</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)\..\libcommon</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4068;4355;4800;4290;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(SolutionDir)\..\libcommon\lib\common-d.lib;odb-__value__(database)-d.lib;odb-d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)\..\libcommon</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4068;4355;4800;4290;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(SolutionDir)\..\libcommon\lib64\common-d.lib;odb-__value__(database)-d.lib;odb-d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)\..\libcommon</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4068;4355;4800;4290;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(SolutionDir)\..\libcommon\lib\common.lib;odb-__value__(database).lib;odb.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)\..\libcommon</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4068;4355;4800;4290;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(SolutionDir)\..\libcommon\lib64\common.lib;odb-__value__(database).lib;odb.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+__custom_build_entry__(
+test1.hxx,
+odb test1.hxx,
+odb.exe --std c++11 --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options1) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1700 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test1.hxx,
+test1-odb.hxx;test1-odb.ixx;test1-odb.cxx;test1.sql;model.xml,
+model.hxx)
+__custom_build_entry__(
+test2.hxx,
+odb test2.hxx,
+odb.exe --std c++11 --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options2) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1700 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test2.hxx,
+test2-odb.hxx;test2-odb.ixx;test2-odb.cxx;test2.sql;model.xml,
+test1-odb.hxx;model.hxx)
+__custom_build_entry__(
+test3.hxx,
+odb test3.hxx,
+odb.exe --std c++11 --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options3) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1700 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test3.hxx,
+test3-odb.hxx;test3-odb.ixx;test3-odb.cxx;test3.sql;test3-002-pre.sql;test3-002-post.sql;test3-003-pre.sql;test3-003-post.sql,
+test2-odb.hxx;model.hxx)
+ </ItemGroup>
+ <ItemGroup>
+__header_entry__(test1-odb.hxx)
+__header_entry__(test1-odb.ixx)
+__header_entry__(test2-odb.hxx)
+__header_entry__(test2-odb.ixx)
+__header_entry__(test3-odb.hxx)
+__header_entry__(test3-odb.ixx)
+__header_entries__(extra_headers)
+ </ItemGroup>
+ <ItemGroup>
+__source_entry__(driver.cxx)
+__source_entry__(test1-odb.cxx)
+__source_entry__(test2-odb.cxx)
+__source_entry__(test3-odb.cxx)
+__source_entries__(extra_sources)
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/odb-tests/evolution/template/template-vc11.vcxproj.filters b/odb-tests/evolution/template/template-vc11.vcxproj.filters
new file mode 100644
index 0000000..d6ac66e
--- /dev/null
+++ b/odb-tests/evolution/template/template-vc11.vcxproj.filters
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{__uuid__()}</UniqueIdentifier>
+ <Extensions>cxx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{__uuid__()}</UniqueIdentifier>
+ <Extensions>h;hxx;ixx;txx</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+__header_filter_entry__(test1.hxx)
+__header_filter_entry__(test1-odb.hxx)
+__header_filter_entry__(test1-odb.ixx)
+__header_filter_entry__(test2.hxx)
+__header_filter_entry__(test2-odb.hxx)
+__header_filter_entry__(test2-odb.ixx)
+__header_filter_entry__(test3.hxx)
+__header_filter_entry__(test3-odb.hxx)
+__header_filter_entry__(test3-odb.ixx)
+__header_filter_entries__(extra_headers)
+ </ItemGroup>
+ <ItemGroup>
+__source_filter_entry__(driver.cxx)
+__source_filter_entry__(test1-odb.cxx)
+__source_filter_entry__(test2-odb.cxx)
+__source_filter_entry__(test3-odb.cxx)
+__source_filter_entries__(extra_sources)
+ </ItemGroup>
+</Project>
diff --git a/odb-tests/evolution/template/template-vc12.vcxproj b/odb-tests/evolution/template/template-vc12.vcxproj
new file mode 100644
index 0000000..9562323
--- /dev/null
+++ b/odb-tests/evolution/template/template-vc12.vcxproj
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{__uuid__()}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>__value__(name)</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v120</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v120</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v120</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v120</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(Configuration)\</OutDir>
+ <TargetName>driver</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(Platform)\$(Configuration)\</OutDir>
+ <TargetName>driver</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(Configuration)\</OutDir>
+ <TargetName>driver</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(Platform)\$(Configuration)\</OutDir>
+ <TargetName>driver</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)\..\libcommon</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4068;4355;4800;4290;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <SDLCheck>true</SDLCheck>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(SolutionDir)\..\libcommon\lib\common-d.lib;odb-__value__(database)-d.lib;odb-d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)\..\libcommon</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4068;4355;4800;4290;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <SDLCheck>true</SDLCheck>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(SolutionDir)\..\libcommon\lib64\common-d.lib;odb-__value__(database)-d.lib;odb-d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)\..\libcommon</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4068;4355;4800;4290;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <SDLCheck>true</SDLCheck>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(SolutionDir)\..\libcommon\lib\common.lib;odb-__value__(database).lib;odb.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)\..\libcommon</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4068;4355;4800;4290;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <SDLCheck>true</SDLCheck>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(SolutionDir)\..\libcommon\lib64\common.lib;odb-__value__(database).lib;odb.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+__custom_build_entry__(
+test1.hxx,
+odb test1.hxx,
+odb.exe --std c++11 --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options1) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1700 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test1.hxx,
+test1-odb.hxx;test1-odb.ixx;test1-odb.cxx;test1.sql;model.xml,
+model.hxx)
+__custom_build_entry__(
+test2.hxx,
+odb test2.hxx,
+odb.exe --std c++11 --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options2) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1700 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test2.hxx,
+test2-odb.hxx;test2-odb.ixx;test2-odb.cxx;test2.sql;model.xml,
+test1-odb.hxx;model.hxx)
+__custom_build_entry__(
+test3.hxx,
+odb test3.hxx,
+odb.exe --std c++11 --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options3) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1700 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test3.hxx,
+test3-odb.hxx;test3-odb.ixx;test3-odb.cxx;test3.sql;test3-002-pre.sql;test3-002-post.sql;test3-003-pre.sql;test3-003-post.sql,
+test2-odb.hxx;model.hxx)
+ </ItemGroup>
+ <ItemGroup>
+__header_entry__(test1-odb.hxx)
+__header_entry__(test1-odb.ixx)
+__header_entry__(test2-odb.hxx)
+__header_entry__(test2-odb.ixx)
+__header_entry__(test3-odb.hxx)
+__header_entry__(test3-odb.ixx)
+__header_entries__(extra_headers)
+ </ItemGroup>
+ <ItemGroup>
+__source_entry__(driver.cxx)
+__source_entry__(test1-odb.cxx)
+__source_entry__(test2-odb.cxx)
+__source_entry__(test3-odb.cxx)
+__source_entries__(extra_sources)
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/odb-tests/evolution/template/template-vc12.vcxproj.filters b/odb-tests/evolution/template/template-vc12.vcxproj.filters
new file mode 100644
index 0000000..d6ac66e
--- /dev/null
+++ b/odb-tests/evolution/template/template-vc12.vcxproj.filters
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{__uuid__()}</UniqueIdentifier>
+ <Extensions>cxx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{__uuid__()}</UniqueIdentifier>
+ <Extensions>h;hxx;ixx;txx</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+__header_filter_entry__(test1.hxx)
+__header_filter_entry__(test1-odb.hxx)
+__header_filter_entry__(test1-odb.ixx)
+__header_filter_entry__(test2.hxx)
+__header_filter_entry__(test2-odb.hxx)
+__header_filter_entry__(test2-odb.ixx)
+__header_filter_entry__(test3.hxx)
+__header_filter_entry__(test3-odb.hxx)
+__header_filter_entry__(test3-odb.ixx)
+__header_filter_entries__(extra_headers)
+ </ItemGroup>
+ <ItemGroup>
+__source_filter_entry__(driver.cxx)
+__source_filter_entry__(test1-odb.cxx)
+__source_filter_entry__(test2-odb.cxx)
+__source_filter_entry__(test3-odb.cxx)
+__source_filter_entries__(extra_sources)
+ </ItemGroup>
+</Project>
diff --git a/odb-tests/evolution/template/template-vc8.vcproj b/odb-tests/evolution/template/template-vc8.vcproj
new file mode 100644
index 0000000..d6c5f15
--- /dev/null
+++ b/odb-tests/evolution/template/template-vc8.vcproj
@@ -0,0 +1,372 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="__value__(name)"
+ ProjectGUID="{__uuid__()}"
+ RootNamespace="__value__(name)"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4068 /wd4355 /wd4800 /wd4290"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)\..\libcommon"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(SolutionDir)\..\libcommon\lib\common-d.lib odb-__value__(database)-d.lib odb-d.lib"
+ OutputFile="$(OutDir)\driver.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4068 /wd4355 /wd4800 /wd4290"
+ AdditionalIncludeDirectories="$(SolutionDir)\..\libcommon"
+ PreprocessorDefinitions="WIN32;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(SolutionDir)\..\libcommon\lib\common.lib odb-__value__(database).lib odb.lib"
+ OutputFile="$(OutDir)\driver.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4068 /wd4355 /wd4800 /wd4290"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)\..\libcommon"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(SolutionDir)\..\libcommon\lib64\common-d.lib odb-__value__(database)-d.lib odb-d.lib"
+ OutputFile="$(OutDir)\driver.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4068 /wd4355 /wd4800 /wd4290"
+ AdditionalIncludeDirectories="$(SolutionDir)\..\libcommon"
+ PreprocessorDefinitions="WIN32;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(SolutionDir)\..\libcommon\lib64\common.lib odb-__value__(database).lib odb.lib"
+ OutputFile="$(OutDir)\driver.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cxx"
+ UniqueIdentifier="{__uuid__()}"
+ >
+__source_entry__(driver.cxx)
+__source_entry__(test1-odb.cxx)
+__source_entry__(test2-odb.cxx)
+__source_entry__(test3-odb.cxx)
+__source_entries__(extra_sources)
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hxx;ixx;txx"
+ UniqueIdentifier="{__uuid__()}"
+ >
+__file_entry_custom_build__(
+test1.hxx,
+odb test1.hxx,
+odb.exe --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options1) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1400 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test1.hxx,
+test1-odb.hxx;test1-odb.ixx;test1-odb.cxx;test1.sql;model.xml,
+model.hxx)
+__file_entry__(test1-odb.hxx)
+__file_entry__(test1-odb.ixx)
+__file_entry_custom_build__(
+test2.hxx,
+odb test2.hxx,
+odb.exe --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options2) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1400 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test2.hxx,
+test2-odb.hxx;test2-odb.ixx;test2-odb.cxx;test2.sql;model.xml,
+test1-odb.hxx;model.hxx)
+__file_entry__(test2-odb.hxx)
+__file_entry__(test2-odb.ixx)
+__file_entry_custom_build__(
+test3.hxx,
+odb test3.hxx,
+odb.exe --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options3) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1400 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test3.hxx,
+test3-odb.hxx;test3-odb.ixx;test3-odb.cxx;test3.sql;test3-002-pre.sql;test3-002-post.sql;test3-003-pre.sql;test3-003-post.sql,
+test2-odb.hxx;model.hxx)
+__file_entry__(test3-odb.hxx)
+__file_entry__(test3-odb.ixx)
+__file_entries__(extra_headers)
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/odb-tests/evolution/template/template-vc9.vcproj b/odb-tests/evolution/template/template-vc9.vcproj
new file mode 100644
index 0000000..9177928
--- /dev/null
+++ b/odb-tests/evolution/template/template-vc9.vcproj
@@ -0,0 +1,379 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="__value__(name)"
+ ProjectGUID="{__uuid__()}"
+ RootNamespace="__value__(name)"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4068 /wd4355 /wd4800 /wd4290"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)\..\libcommon"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(SolutionDir)\..\libcommon\lib\common-d.lib odb-__value__(database)-d.lib odb-d.lib"
+ OutputFile="$(OutDir)\driver.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4068 /wd4355 /wd4800 /wd4290"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="$(SolutionDir)\..\libcommon"
+ PreprocessorDefinitions="WIN32;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(SolutionDir)\..\libcommon\lib\common.lib odb-__value__(database).lib odb.lib"
+ OutputFile="$(OutDir)\driver.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4068 /wd4355 /wd4800 /wd4290"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)\..\libcommon"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(SolutionDir)\..\libcommon\lib64\common-d.lib odb-__value__(database)-d.lib odb-d.lib"
+ OutputFile="$(OutDir)\driver.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4068 /wd4355 /wd4800 /wd4290"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="$(SolutionDir)\..\libcommon"
+ PreprocessorDefinitions="WIN32;_CONSOLE;__upcase__(database_)__upcase__(__value__(database));HAVE_CONFIG_VC_H"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(SolutionDir)\..\libcommon\lib64\common.lib odb-__value__(database).lib odb.lib"
+ OutputFile="$(OutDir)\driver.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cxx"
+ UniqueIdentifier="{__uuid__()}"
+ >
+__source_entry__(driver.cxx)
+__source_entry__(test1-odb.cxx)
+__source_entry__(test2-odb.cxx)
+__source_entry__(test3-odb.cxx)
+__source_entries__(extra_sources)
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hxx;ixx;txx"
+ UniqueIdentifier="{__uuid__()}"
+ >
+__file_entry_custom_build__(
+test1.hxx,
+odb test1.hxx,
+odb.exe --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options1) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1500 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test1.hxx,
+test1-odb.hxx;test1-odb.ixx;test1-odb.cxx;test1.sql;model.xml,
+model.hxx)
+__file_entry__(test1-odb.hxx)
+__file_entry__(test1-odb.ixx)
+__file_entry_custom_build__(
+test2.hxx,
+odb test2.hxx,
+odb.exe --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options2) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1500 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test2.hxx,
+test2-odb.hxx;test2-odb.ixx;test2-odb.cxx;test2.sql;model.xml,
+test1-odb.hxx;model.hxx)
+__file_entry__(test2-odb.hxx)
+__file_entry__(test2-odb.ixx)
+__file_entry_custom_build__(
+test3.hxx,
+odb test3.hxx,
+odb.exe --database __value__(database) __xml__(__shell_quotes__(__value__(odb_options3) --changelog model.xml -DHAVE_CONFIG_VC_H -DODB_MSC_VER=1500 __upcase__(-Ddatabase_)__upcase__(__value__(database)) -I$(SolutionDir)\..\libcommon)) test3.hxx,
+test3-odb.hxx;test3-odb.ixx;test3-odb.cxx;test3.sql;test3-002-pre.sql;test3-002-post.sql;test3-003-pre.sql;test3-003-post.sql,
+test2-odb.hxx;model.hxx)
+__file_entry__(test3-odb.hxx)
+__file_entry__(test3-odb.ixx)
+__file_entries__(extra_headers)
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/odb-tests/evolution/template/test1.hxx b/odb-tests/evolution/template/test1.hxx
new file mode 100644
index 0000000..238b686
--- /dev/null
+++ b/odb-tests/evolution/template/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/template/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/template/test2.hxx b/odb-tests/evolution/template/test2.hxx
new file mode 100644
index 0000000..ec982f5
--- /dev/null
+++ b/odb-tests/evolution/template/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/template/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/template/test3.hxx b/odb-tests/evolution/template/test3.hxx
new file mode 100644
index 0000000..50f3882
--- /dev/null
+++ b/odb-tests/evolution/template/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/template/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX
diff --git a/odb-tests/evolution/version/driver.cxx b/odb-tests/evolution/version/driver.cxx
new file mode 100644
index 0000000..236c9b4
--- /dev/null
+++ b/odb-tests/evolution/version/driver.cxx
@@ -0,0 +1,156 @@
+// file : evolution/version/driver.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test schema version access via the database instance.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <common/config.hxx> // DATABASE_XXX
+#include <common/common.hxx>
+
+#include "test2.hxx"
+#include "test3.hxx"
+#include "test2-odb.hxx"
+#include "test3-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv, false));
+ bool embedded (schema_catalog::exists (*db));
+
+ // 1 - base version
+ // 2 - migration
+ // 3 - current version
+ //
+ unsigned short pass (*argv[argc - 1] - '0');
+
+ switch (pass)
+ {
+ case 1:
+ {
+ using namespace v2;
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::drop_schema (*db);
+
+ assert (db->schema_version () == 0);
+
+ schema_catalog::create_schema (*db, "", false);
+
+ assert (db->schema_version () == 1 && !db->schema_migration ());
+
+ schema_catalog::migrate_schema (*db, 2);
+ t.commit ();
+ }
+
+ assert (db->schema_version () == 2 && !db->schema_migration ());
+
+ {
+ transaction t (db->begin ());
+ object1 o1 (1);
+ o1.num = 123;
+ db->persist (o1);
+ t.commit ();
+ }
+ break;
+ }
+ case 2:
+ {
+ using namespace v2;
+ using namespace v3;
+
+ if (embedded)
+ {
+ assert (db->schema_version () == 2 && !db->schema_migration ());
+
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_pre (*db, 3);
+ t.commit ();
+ }
+
+ assert (db->schema_version () == 3 && db->schema_migration ());
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object1> o1 (db->load<object1> (1));
+ object2 o2 (1);
+ o2.num = o1->num;
+ db->persist (o2);
+ t.commit ();
+ }
+
+ if (embedded)
+ {
+ transaction t (db->begin ());
+ schema_catalog::migrate_schema_post (*db, 3);
+ t.commit ();
+
+ assert (db->schema_version () == 3 && !db->schema_migration ());
+ }
+ break;
+ }
+ case 3:
+ {
+ using namespace v3;
+
+ // In transaction.
+ //
+ {
+ transaction t (db->begin ());
+ assert (db->schema_version () == 3 && !db->schema_migration ());
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<object2> o2 (db->load<object2> (1));
+ assert (o2->num == 123);
+ t.commit ();
+ }
+
+ // Test the case where there is still no version table.
+ //
+ db->schema_version_migration (0, false);
+
+ {
+ transaction t (db->begin ());
+
+#ifdef DATABASE_ORACLE
+ db->execute ("DROP TABLE \"schema_version\"");
+#else
+ db->execute ("DROP TABLE schema_version");
+#endif
+ t.commit ();
+ }
+
+ assert (db->schema_version () == 0);
+ break;
+ }
+ default:
+ {
+ cerr << "unknown pass number '" << argv[argc - 1] << "'" << endl;
+ return 1;
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/odb-tests/evolution/version/model.hxx b/odb-tests/evolution/version/model.hxx
new file mode 100644
index 0000000..cdda00e
--- /dev/null
+++ b/odb-tests/evolution/version/model.hxx
@@ -0,0 +1,45 @@
+// file : evolution/version/model.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef MODEL_VERSION
+# error model.hxx included directly
+#endif
+
+#include <odb/core.hxx>
+
+#pragma db model version(1, MODEL_VERSION)
+
+#define MODEL_NAMESPACE_IMPL(V) v##V
+#define MODEL_NAMESPACE(V) MODEL_NAMESPACE_IMPL(V)
+
+namespace MODEL_NAMESPACE(MODEL_VERSION)
+{
+#if MODEL_VERSION == 2
+ #pragma db object
+ struct object1
+ {
+ object1 (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ int num;
+ };
+#endif
+
+#if MODEL_VERSION == 3
+ #pragma db object
+ struct object2
+ {
+ object2 (unsigned long id = 0): id_ (id) {}
+
+ #pragma db id
+ unsigned long id_;
+
+ int num;
+ };
+#endif
+}
+
+#undef MODEL_NAMESPACE
+#undef MODEL_NAMESPACE_IMPL
diff --git a/odb-tests/evolution/version/test1.hxx b/odb-tests/evolution/version/test1.hxx
new file mode 100644
index 0000000..a50e54c
--- /dev/null
+++ b/odb-tests/evolution/version/test1.hxx
@@ -0,0 +1,9 @@
+// file : evolution/version/test1.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST1_HXX
+#define TEST1_HXX
+
+#pragma db model version(1, 1)
+
+#endif // TEST1_HXX
diff --git a/odb-tests/evolution/version/test2.hxx b/odb-tests/evolution/version/test2.hxx
new file mode 100644
index 0000000..f7fc1b7
--- /dev/null
+++ b/odb-tests/evolution/version/test2.hxx
@@ -0,0 +1,11 @@
+// file : evolution/version/test2.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST2_HXX
+#define TEST2_HXX
+
+#define MODEL_VERSION 2
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST2_HXX
diff --git a/odb-tests/evolution/version/test3.hxx b/odb-tests/evolution/version/test3.hxx
new file mode 100644
index 0000000..364ee31
--- /dev/null
+++ b/odb-tests/evolution/version/test3.hxx
@@ -0,0 +1,11 @@
+// file : evolution/version/test3.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST3_HXX
+#define TEST3_HXX
+
+#define MODEL_VERSION 3
+#include "model.hxx"
+#undef MODEL_VERSION
+
+#endif // TEST3_HXX