aboutsummaryrefslogtreecommitdiff
path: root/bdep/database.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-03-08 18:06:26 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-03-08 18:06:26 +0200
commitdf5e58e6e5eb2727a185bf9a98a462c18fa3a83d (patch)
treefb0cc76643865390ac3e45462d51ea02575a3175 /bdep/database.cxx
parentf9ebe2d1e920df001be2dd543a63677f8728f53d (diff)
Setup project database infrastructure
Diffstat (limited to 'bdep/database.cxx')
-rw-r--r--bdep/database.cxx88
1 files changed, 88 insertions, 0 deletions
diff --git a/bdep/database.cxx b/bdep/database.cxx
new file mode 100644
index 0000000..c456961
--- /dev/null
+++ b/bdep/database.cxx
@@ -0,0 +1,88 @@
+// file : bdep/database.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <bdep/database.hxx>
+
+#include <odb/schema-catalog.hxx>
+#include <odb/sqlite/exceptions.hxx>
+
+#include <bdep/diagnostics.hxx>
+
+using namespace std;
+
+namespace bdep
+{
+ using namespace odb::sqlite;
+ using odb::schema_catalog;
+
+ database
+ open (const dir_path& d, tracer& tr, bool create)
+ {
+ tracer trace ("open");
+
+ path f (d / bdep_dir / "bdep.sqlite3");
+
+ if (!create && !exists (f))
+ fail << d << " does not look like an initialized project directory" <<
+ info << "run 'bdep init' to initialize";
+
+ try
+ {
+ // We don't need the thread pool.
+ //
+ unique_ptr<connection_factory> cf (new single_connection_factory);
+
+ database db (f.string (),
+ SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0),
+ true, // Enable FKs.
+ "", // Default VFS.
+ move (cf));
+
+ db.tracer (trace);
+
+ // Lock the database for as long as the connection is active. First we
+ // set locking_mode to EXCLUSIVE which instructs SQLite not to release
+ // any locks until the connection is closed. Then we force SQLite to
+ // acquire the write lock by starting exclusive transaction. See the
+ // locking_mode pragma documentation for details. This will also fail if
+ // the database is inaccessible (e.g., file does not exist, already used
+ // by another process, etc).
+ //
+ try
+ {
+ db.connection ()->execute ("PRAGMA locking_mode = EXCLUSIVE");
+ transaction t (db.begin_exclusive ());
+
+ if (create)
+ {
+ // Create the new schema.
+ //
+ if (db.schema_version () != 0)
+ fail << f << ": already has database schema";
+
+ schema_catalog::create_schema (db);
+ }
+ else
+ {
+ // Migrate the database if necessary.
+ //
+ schema_catalog::migrate (db);
+ }
+
+ t.commit ();
+ }
+ catch (odb::timeout&)
+ {
+ fail << "project " << d << " is already used by another process";
+ }
+
+ db.tracer (tr); // Switch to the caller's tracer.
+ return db;
+ }
+ catch (const database_exception& e)
+ {
+ fail << f << ": " << e.message () << endf;
+ }
+ }
+}