aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2013-04-25 07:35:45 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2013-04-25 07:35:45 +0200
commitd062cc21ae1dc530a21017dfbf841e557d64c6c3 (patch)
treed75ee67461a7a9538a143ac4cee68d760cb06680
parentfce0bab486c0086cf0f799dc4a2b6f11376c23e1 (diff)
Add support for schema version table
-rw-r--r--odb/sqlite/database.cxx92
-rw-r--r--odb/sqlite/database.hxx8
2 files changed, 99 insertions, 1 deletions
diff --git a/odb/sqlite/database.cxx b/odb/sqlite/database.cxx
index e8e5c77..d5399f7 100644
--- a/odb/sqlite/database.cxx
+++ b/odb/sqlite/database.cxx
@@ -6,11 +6,16 @@
# include <odb/details/win32/windows.hxx> // WideCharToMultiByte
#endif
+#include <sqlite3.h>
+
+#include <cassert>
#include <sstream>
#include <odb/sqlite/database.hxx>
#include <odb/sqlite/connection.hxx>
#include <odb/sqlite/connection-factory.hxx>
+#include <odb/sqlite/statement.hxx>
+#include <odb/sqlite/transaction.hxx>
#include <odb/sqlite/error.hxx>
#include <odb/sqlite/exceptions.hxx>
@@ -177,5 +182,92 @@ namespace odb
connection_ptr c (factory_->connect ());
return c.release ();
}
+
+ const database::schema_version_info& database::
+ load_schema_version (const string& name) const
+ {
+ schema_version_info& svi (schema_version_map_[name]);
+
+ // Construct the SELECT statement text.
+ //
+ string text ("SELECT \"version\", \"migration\" FROM ");
+
+ if (!svi.version_table.empty ())
+ text += svi.version_table; // Already quoted.
+ else if (!schema_version_table_.empty ())
+ text += schema_version_table_; // Already quoted.
+ else
+ text += "\"schema_version\"";
+
+ text += " WHERE \"name\" = ?";
+
+ // Bind parameters and results.
+ //
+ size_t psize[1] = {name.size ()};
+ bind pbind[1] = {{bind::text,
+ const_cast<char*> (name.c_str ()),
+ &psize[0],
+ 0, 0, 0}};
+ binding param (pbind, 1);
+ param.version++;
+
+ long long migration;
+ bool rnull[2];
+ bind rbind[2] = {{bind::integer, &svi.version, 0, 0, &rnull[0], 0},
+ {bind::integer, &migration, 0, 0, &rnull[1], 0}};
+ binding result (rbind, 2);
+ result.version++;
+
+ // If we are not in transaction, SQLite will start an implicit one
+ // which suits us just fine.
+ //
+ connection_ptr cp;
+ if (!transaction::has_current ())
+ cp = factory_->connect ();
+
+ sqlite::connection& c (
+ cp != 0 ? *cp : transaction::current ().connection ());
+
+ try
+ {
+ select_statement st (c, text, param, result);
+ st.execute ();
+ auto_result ar (st);
+
+ switch (st.fetch ())
+ {
+ case select_statement::success:
+ {
+ svi.migration = migration != 0;
+ assert (st.fetch () == select_statement::no_data);
+ break;
+ }
+ case select_statement::no_data:
+ {
+ svi.version = 0; // No schema.
+ break;
+ }
+ case select_statement::truncated:
+ {
+ assert (false);
+ break;
+ }
+ }
+ }
+ catch (const database_exception& e)
+ {
+ // Try to detect the case where there is no version table. SQLite
+ // doesn't have an extended error code for this so we have to use
+ // the error text.
+ //
+ if (e.error () == SQLITE_ERROR &&
+ e.message ().compare (0, 14, "no such table:") == 0)
+ svi.version = 0; // No schema.
+ else
+ throw;
+ }
+
+ return svi;
+ }
}
}
diff --git a/odb/sqlite/database.hxx b/odb/sqlite/database.hxx
index ee758e5..0471b64 100644
--- a/odb/sqlite/database.hxx
+++ b/odb/sqlite/database.hxx
@@ -349,9 +349,15 @@ namespace odb
using odb::database::tracer;
- public:
+ // Database schema version.
+ //
+ protected:
+ virtual const schema_version_info&
+ load_schema_version (const std::string& schema_name) const;
+
// Database id constant (useful for meta-programming).
//
+ public:
static const odb::database_id database_id = id_sqlite;
public: